Esempio n. 1
0
        private static object[] CreateCompositePk(IEntity child, DbRelation fk)
        {
            // Child and parent columns in the relation are in the same order.
            // However, that order may not match the order of PK definition in the parent's IDbTable class.
            // Thus, the FK values may have to be reordered to be used as PK.
            IDbColumn[] orderedPkFields = fk.Parent.PrimaryKey.ToArray();
            object[] pk = new object[orderedPkFields.Length];
            int nullValCount = 0;
            for (int idxOrderedPkPart = 0; idxOrderedPkPart < orderedPkFields.Length; idxOrderedPkPart++)
            {
                IDbColumn currPkField = orderedPkFields[idxOrderedPkPart];
                int positionOfCurrentPkColumnInRelation = IndexOfColumnInArray(fk.ParentPrimaryKey, currPkField.ColumnName);
                IDbColumn currFkField = fk.ChildForeignKey[positionOfCurrentPkColumnInRelation];
                object fkPart = child.GetField(currFkField);
                pk[idxOrderedPkPart] = fkPart;

                if (fkPart == null)
                    nullValCount++;
            }

            bool fkIsSet = (nullValCount == 0);
            if (!fkIsSet)
            {
                bool allFkFieldsAreNull = (nullValCount == orderedPkFields.Length);
                if (allFkFieldsAreNull)
                    pk = null;
                else
                    throw new ArgumentException(Messages.PkUtil_FkMustBeCompleteOrNull, "child");
            }

            return pk;
        }
        /// <summary>
        /// Initializes a new instance of the ManyToManyRelation class.
        /// </summary>
        /// <param name="firstTableToJunction">Relation between the junction table and the first primary table.</param>
        /// <param name="secondTableToJunction">Relation between the junction table and the second primary table.</param>
        public ManyToManyRelation(DbRelation firstTableToJunction, DbRelation secondTableToJunction)
        {
            if (!firstTableToJunction.Child.HasEqualAliasAndNameAs(secondTableToJunction.Child))
                throw new InvalidOperationException(Messages.ManyToManyRelation_RelationsSpecifyDiffJunctionTables);

            this.firstTableToJunction = firstTableToJunction;
            this.secondTableToJunction = secondTableToJunction;
        }
Esempio n. 3
0
 private static object[] CreateSingleFieldPk(IEntity child, DbRelation fk)
 {
     object[] pk;
     // Complex algorithm not required if simple FK is used.
     object fkVal = child.GetField(fk.ChildForeignKey[0]);
     pk = (fkVal != null) ? new object[] { fkVal } : null;
     return pk;
 }
Esempio n. 4
0
        /// <summary>
        /// Creates an object array which represents PK with the FK values stored in the given child.
        /// </summary>
        /// <returns>PK or <b>null</b> if child's FK is not set.</returns>
        /// <remarks>An exception is generated if a child contains an invalid, i.e. partially set, FK.
        /// Either all, or none of the FK properties must be set.</remarks>
        public static object[] CreatePkFromFk(IEntity child, DbRelation fk)
        {
            object[] pk;
            if (fk.ChildForeignKey.Length == 1)
                pk = CreateSingleFieldPk(child, fk);
            else
                pk = CreateCompositePk(child, fk);

            return pk;
        }
Esempio n. 5
0
        internal FromClause(IDbTable firstTable, DbRelation[] orderedRelations, TableWithJoinMode[] orderedFromTablesIncludingFirstTable)
        {
            this.FromTable = firstTable;

            JoinClause[] joins = new JoinClause[orderedRelations.Length];
            for (int relationIdx = 0; relationIdx < orderedRelations.Length; relationIdx++)
            {
                int joinedTableIdx = relationIdx + 1;
                joins[relationIdx] = new JoinClause(orderedRelations[relationIdx], orderedFromTablesIncludingFirstTable[joinedTableIdx].Table, orderedFromTablesIncludingFirstTable[joinedTableIdx].JoinAsOuter);
            }

            this.Joins = joins;
            this.JoinCount = joins.Length;
        }
        /// <summary>
        /// Adds a relation with a unique name to the collection.
        /// If a relation with the same name already exists, a new name is automatically set.
        /// </summary>
        /// <param name="relation">New relation.</param>
        public void Add(DbRelation relation)
        {
            int i = 2;
            while (GetByName(relation.Name) != null)
            {
                relation.Name += "_" + i.ToString(CultureInfo.InvariantCulture);
                i++;
            }

            this.list.Add(relation);

            if (this.tables.Contains(relation.Parent) == false)
                this.tables.Add(relation.Parent);

            if (this.tables.Contains(relation.Child) == false)
                this.tables.Add(relation.Child);
        }
Esempio n. 7
0
 /// <summary>
 /// Gets the parent entity defined by the given foreign key.
 /// <seealso cref="RelationshipNavigationEnabled"/>
 /// </summary>
 /// <param name="foreignKey">FK. Child table of the given FK must be the current entity's table;
 /// otherwise an exception is generated.</param>
 /// <returns>Parent entity. <b>Null</b> if the FK fields haven't been set or if the entity with the given key values doesn't exist.</returns>
 /// <remarks>If the entity hasn't been initialized yet but the FK values are set and relationship navigation
 /// is enabled then the method will automatically fetch it from the data source.</remarks>
 public abstract IEntity GetParent(DbRelation foreignKey);
Esempio n. 8
0
 /// <summary>Not implemented.</summary>
 string IDbTable.GetParentProperty(DbRelation fk, IDbColumn parentColumn)
 {
     throw new NotImplementedException();
 }
Esempio n. 9
0
		/// <summary>
		/// Creates a deep copy of current instance.
		/// </summary>
		public DbRelation Clone()
		{			
			DbRelation clone = new DbRelation();
			clone.CopyFrom(this);
			return clone;
		}
Esempio n. 10
0
        private static bool GetNextRelationAndTable(DbRelationCollection allRelations, List<JoinMode> allJoinModes, TableWithJoinMode[] usedTables, out DbRelation nextRelation, out TableWithJoinMode nextTable)
        {
            nextRelation = null;
            nextTable = null;
            for (int idxRelation = 0; idxRelation < allRelations.Count; idxRelation++)
            {
                DbRelation currentRelation = allRelations[idxRelation];

                IDbTable newTableCandidate = null;
                TableWithJoinMode alreadyUsedTableFromCurrentRelation = null;
                bool connectAsOuter = false;
                int numOfTablesCurrentRelationConnects = 0;

                // Check how many of the used tables current relation connects.
                for (int idxTable = 0; idxTable < usedTables.Length; idxTable++)
                {
                    if (usedTables[idxTable] == null)
                        continue;

                    if (currentRelation.Parent.HasEqualAliasAndNameAs(usedTables[idxTable].Table))
                    {
                        // Parent table is already in the ordered from tables list.

                        numOfTablesCurrentRelationConnects++;
                        newTableCandidate = currentRelation.Child;
                        alreadyUsedTableFromCurrentRelation = usedTables[idxTable];
                        if (allJoinModes[idxRelation].ChildrenAsOuter == true)
                            connectAsOuter = true;
                    }

                    if (currentRelation.Child.HasEqualAliasAndNameAs(usedTables[idxTable].Table))
                    {
                        // Child table is already in the ordered from tables list.

                        numOfTablesCurrentRelationConnects++;
                        newTableCandidate = currentRelation.Parent;
                        alreadyUsedTableFromCurrentRelation = usedTables[idxTable];
                        if (allJoinModes[idxRelation].ParentAsOuter == true)
                            connectAsOuter = true;
                    }
                }

                // If current relation connects only one used table than the other one is a new table.				
                // Return the new relation and table.
                if (numOfTablesCurrentRelationConnects == 1)
                {
                    // If the already used table is connected as outer then the new one MUST be outer, too.
                    if (alreadyUsedTableFromCurrentRelation.JoinAsOuter == true)
                        connectAsOuter = true;

                    nextRelation = currentRelation;
                    nextTable = new TableWithJoinMode(newTableCandidate, connectAsOuter);
                    return true;
                }
            }

            return false;
        }
Esempio n. 11
0
 private void EnsureTheRelationIsNotAlreadyInTheBucket(DbRelation newRelation)
 {
     bool alreadyInTheBucket = (this.relations[newRelation.Parent, newRelation.Child] != null);
     if (alreadyInTheBucket)
     {
         //throw new InvalidOperationException("The bucket already contains a relation that connects the " + newRelation.Parent.Alias + " and " + newRelation.Child.Alias + " tables.");
         throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, Messages.RelationBucket_AlreadyConnectsXAndYTables, newRelation.Parent.Alias, newRelation.Child.Alias));
     }
 }
Esempio n. 12
0
 /// <summary>
 /// Creates a deep copy of current instance.
 /// </summary>
 /// <param name="setPrefixedAliasesForChildColumns">Specifies whether child columns in cloned relation will have prefixed aliases. 
 /// This parameter overrides the value set in <see cref="IDbTable.ColumnAliasesArePrefixed"/> property.</param>
 /// <param name="setPrefixedAliasesForParentColumns">Specifies whether parent columns in cloned relation will have prefixed aliases. 
 /// This parameter overrides the value set in <see cref="IDbTable.ColumnAliasesArePrefixed"/> property.</param>
 public DbRelation Clone(bool setPrefixedAliasesForChildColumns, bool setPrefixedAliasesForParentColumns)
 {
     DbRelation clone = new DbRelation();
     clone.CopyFrom(this, null, setPrefixedAliasesForChildColumns, null, setPrefixedAliasesForParentColumns);
     return clone;
 }
Esempio n. 13
0
        private static int IndexOfRelation(DbRelation[] foreignKeys, DbRelation rel)
        {
            for (int idx = 0; idx < foreignKeys.Length; idx++)
            {
                if (rel.HasEqualForeignKeyFieldsAs(foreignKeys[idx]))
                    return idx;
            }

            return -1;
        }
Esempio n. 14
0
 private void CopyFrom(DbRelation source, string childAlias, bool setPrefixedAliasesForChildColumns, string parentAlias, bool setPrefixedAliasesForParentColumns)
 {
     this.name = source.name;
     this.child = source.child.Clone(childAlias ?? source.child.Alias, setPrefixedAliasesForChildColumns);
     this.childFK = GetColumns(this.child, source.childFK);
     this.parent = source.parent.Clone(parentAlias ?? source.parent.Alias, setPrefixedAliasesForParentColumns);
     this.parentPK = GetColumns(this.parent, source.parentPK);            
 }
Esempio n. 15
0
 /// <summary>
 /// Creates a deep copy of current instance.
 /// </summary>
 /// <param name="childAlias">New child table alias. If <b>null</b> then current alias is used.</param>
 /// <param name="setPrefixedAliasesForChildColumns">Specifies whether child columns in cloned relation will have prefixed aliases. 
 /// This parameter overrides the value set in <see cref="IDbTable.ColumnAliasesArePrefixed"/> property.</param>
 /// <param name="parentAlias">New parent table alias. If <b>null</b> then current alias is used.</param>
 /// <param name="setPrefixedAliasesForParentColumns">Specifies whether parent columns in cloned relation will have prefixed aliases. 
 /// This parameter overrides the value set in <see cref="IDbTable.ColumnAliasesArePrefixed"/> property.</param>
 public DbRelation Clone(string childAlias, bool setPrefixedAliasesForChildColumns, string parentAlias, bool setPrefixedAliasesForParentColumns)
 {
     DbRelation clone = new DbRelation();
     clone.CopyFrom(this, childAlias, setPrefixedAliasesForChildColumns, parentAlias, setPrefixedAliasesForParentColumns);
     return clone;
 }
Esempio n. 16
0
 /// <summary>
 /// Sets the given value into the member that represents the parent entity defined by the foreign key.
 /// </summary>
 /// <param name="foreignKey">FK. Child table of the given FK must be the current entity's table;
 /// otherwise an exception is generated.</param>
 /// <param name="entity">Parent entity. Must be compatibile with the targeted member.</param>
 /// <remarks>Inherited classes must implement the required logic.</remarks>
 public abstract void SetParent(DbRelation foreignKey, IEntity entity);
Esempio n. 17
0
 /// <summary>
 /// Adds a relation to the bucket. 
 /// </summary>
 /// <param name="relation">Relation.</param>
 /// <remarks>Child table is connected as outer. Parent table is connected as outer if foreign 
 /// key is made of exactly one nullable column. If parallel relations are used then tables must 
 /// use aliases, otherwise an error will occur.</remarks>
 /// <exception cref="ArgumentException">is generated if the bucket already contains a relation
 /// which contains the same tables with the same aliases as the new relation.</exception>
 public void Add(DbRelation relation)
 {
     EnsureTheRelationIsNotAlreadyInTheBucket(relation);
     this.relations.Add(relation);
     bool parentAsOuter = IsNullableFk(relation.ChildForeignKey);
     this.joinModes.Add(new JoinMode(parentAsOuter, true));
 }
Esempio n. 18
0
 /// <summary>
 /// Gets the full property path for the specified parent entity field.
 /// </summary>
 /// <param name="fk">Relation to the parent entity.</param>
 /// <param name="parentColumn">Parent entity field. If null only property name generated for parent entity is returned.</param>
 /// <returns>Parent entity property name followed by dot operator and parent field property name if <b>parentColumn</b> is defined; otherwise only parent entity property name.</returns>
 /// <remarks>Eg. the following code snippet returns "RegionParent.RegionDescription" property path.
 /// <code>
 /// public string GetRegionDescriptionPropertyForDataBinder()
 /// {
 ///		TerritoriesMeta territories = new TerritoriesMeta();
 ///		RegionMeta regions = new RegionMeta();
 ///		return territories.GetParentProperty(territories.FK_RegionID, regions.RegionDescription);
 /// }
 /// </code>
 /// </remarks>
 public string GetParentProperty(DbRelation fk, IDbColumn parentColumn)
 {
     int idxParent = IndexOfRelation(fk);
     string fullPropertyName = (idxParent >= 0) ? GetParentProperty(idxParent, parentColumn) : null;
     return fullPropertyName;
 }
Esempio n. 19
0
		private void CopyFrom(DbRelation source)
		{
			this.name = source.name;
			this.parent = source.parent.Clone(source.parent.Alias, source.parent.ColumnAliasesArePrefixed);
			//EnsureEqualColumnAliases(source.parent, this.parent);
			this.parentPK = GetColumns(this.parent, source.parentPK);
			this.child = source.child.Clone(source.child.Alias, source.child.ColumnAliasesArePrefixed);
			//EnsureEqualColumnAliases(this.child, source.child);
			this.childFK = GetColumns(this.child, source.childFK);
		}
Esempio n. 20
0
 /// <summary>
 /// Adds a relation to the bucket.
 /// </summary>
 /// <remarks>If parallel relations are used then tables must use aliases, otherwise an error will occur.</remarks>
 /// <param name="relation">Relation.</param>
 /// <param name="parentAsOuter">Specifies whether the parent table is connected as outer.</param>
 /// <param name="childrenAsOuter">Specifies whether the child table is connected as outer.</param>
 /// <remarks>Child table is connected as outer. Parent table is connected as outer if foreign 
 /// key is made of exactly one nullable column. If parallel relations are used then tables must 
 /// use aliases, otherwise an error will occur.</remarks>
 /// <exception cref="ArgumentException">is generated if the bucket already contains a relation
 /// which contains the same tables with the same aliases as the new relation.</exception>
 public void Add(DbRelation relation, bool parentAsOuter, bool childrenAsOuter)
 {
     EnsureTheRelationIsNotAlreadyInTheBucket(relation);
     this.relations.Add(relation);
     this.joinModes.Add(new JoinMode(parentAsOuter, childrenAsOuter));
 }
Esempio n. 21
0
        private int IndexOfRelation(DbRelation rel)
        {
            for (int idx = 0; idx < this.ForeignKeys.Length; idx++)
            {
                if (rel.HasEqualForeignKeyFieldsAs(this.ForeignKeys[idx]))
                    return idx;
            }

            return -1;
        }
Esempio n. 22
0
 /// <summary>
 /// Adds a relation to the bucket.
 /// </summary>
 /// <param name="parent">Parent/master table.</param>
 /// <param name="child">Child/data table.</param>
 /// <param name="childForeignKey">Child foreign key.</param>
 /// <remarks>Child table is connected as outer. Parent table is connected as outer if foreign 
 /// key is made of exactly one nullable column. If parallel relations are used then tables must 
 /// use aliases, otherwise an error will occur.</remarks>
 /// <exception cref="ArgumentException">is generated if the bucket already contains a relation
 /// which contains the same tables with the same aliases as the new relation.</exception>
 public void Add(IDbTable parent, IDbTable child, IDbColumn childForeignKey)
 {
     DbRelation relation = new DbRelation(parent, child, childForeignKey);
     Add(relation);
 }
Esempio n. 23
0
 /// <summary>
 /// Create instance with parent relation.
 /// </summary>
 /// <param name="column">Column to create.</param>
 /// <param name="parentRelation">Relation to column.</param>
 public ColumnKey(IDbColumn column, DbRelation parentRelation)
 {
     this.Column = column;
     this.ParentRelation = parentRelation;
 }
Esempio n. 24
0
        private static void SortRelationsAndJoinModes(DbRelationCollection allRelations, List<JoinMode> allJoinModes, IDbTable firstTable, out DbRelation[] orderedRelations, out TableWithJoinMode[] orderedFromTables)
        {
            // Sorts relations in a fashion so that only INNER and LEFT OUTER joins are used. RIGHT joins will never be required.

            orderedRelations = new DbRelation[allRelations.Count];
            int relationIdx = 0;
            orderedFromTables = new TableWithJoinMode[allJoinModes.Count + 1];
            int fromIdx = 0;

            // JoinAsOuter property doesn't doesn't affect 1st table.
            orderedFromTables[fromIdx] = new TableWithJoinMode(firstTable, false);
            fromIdx++;

            DbRelation nextRelation;
            TableWithJoinMode nextTable;
            while (GetNextRelationAndTable(allRelations, allJoinModes, orderedFromTables, out nextRelation, out nextTable))
            {
                orderedRelations[relationIdx++] = nextRelation;
                orderedFromTables[fromIdx++] = nextTable;
            }
        }
Esempio n. 25
0
 internal JoinClause(DbRelation relation, IDbTable joinedTable, bool isLeftOuterJoin)
 {
     this.Relation = relation;
     this.JoinedTable = joinedTable;
     this.IsLeftOuterJoin = isLeftOuterJoin;
 }
Esempio n. 26
0
 /// <summary>
 /// Initializes a new instance of the RelationBucket class.
 /// </summary>
 /// <param name="firstRelation">First/initial relation added to the bucket using <see cref="Add(DbRelation)"/> method.</param>
 public RelationBucket(DbRelation firstRelation)
 {
     Add(firstRelation);
 }
Esempio n. 27
0
		/// <summary>
		/// Checks whether the two relations use the same child FK fields.
		/// </summary>
		/// <param name="otherRelation">Other relation.</param>
		/// <returns>True if all FK fields have been matched; false otherwise.</returns>
		public bool HasEqualForeignKeyFieldsAs(DbRelation otherRelation)
		{	
			// Check if both relations use the same table as a child object.
			// Check only TableNames. Aliases may differ.
			if (this.child.TableName != otherRelation.child.TableName)
				return false;

			// FK count must be the same.
			if (this.childFK.Length != otherRelation.childFK.Length)
				return false;

			// Field order may be different, so all combinations must be tested.
			int matchedFkFieldsCount = 0;
			for (int i=0; i<this.childFK.Length; i++)
			{
				for (int j=0; j<otherRelation.childFK.Length; j++)
				{
					if (this.childFK[i].ColumnName ==  otherRelation.childFK[j].ColumnName)
					{
						matchedFkFieldsCount++;
						break;
					}
				}
			}

			bool allFkFieldsAreMatched = (matchedFkFieldsCount == this.childFK.Length);
			return allFkFieldsAreMatched;
		}