Exemple #1
0
        internal ForeignKeyConstraint(md.RelationshipType relType, md.RelationshipSet relationshipSet, md.ReferentialConstraint constraint)
        {
            md.AssociationSet       assocSet = relationshipSet as md.AssociationSet;
            md.AssociationEndMember fromEnd  = constraint.FromRole as md.AssociationEndMember;
            md.AssociationEndMember toEnd    = constraint.ToRole as md.AssociationEndMember;

            // Currently only Associations are supported
            if (null == assocSet || null == fromEnd || null == toEnd)
            {
                throw EntityUtil.NotSupported();
            }

            m_constraint = constraint;
            md.EntitySet parent = System.Data.Common.Utils.MetadataHelper.GetEntitySetAtEnd(assocSet, fromEnd); // relationshipSet.GetRelationshipEndExtent(constraint.FromRole);
            md.EntitySet child  = System.Data.Common.Utils.MetadataHelper.GetEntitySetAtEnd(assocSet, toEnd);   // relationshipSet.GetRelationshipEndExtent(constraint.ToRole);
            m_extentPair = new ExtentPair(parent, child);
            m_childKeys  = new List <string>();
            foreach (md.EdmProperty prop in constraint.ToProperties)
            {
                m_childKeys.Add(prop.Name);
            }

            m_parentKeys = new List <string>();
            foreach (md.EdmProperty prop in constraint.FromProperties)
            {
                m_parentKeys.Add(prop.Name);
            }

            PlanCompiler.Assert((md.RelationshipMultiplicity.ZeroOrOne == fromEnd.RelationshipMultiplicity || md.RelationshipMultiplicity.One == fromEnd.RelationshipMultiplicity), "from-end of relationship constraint cannot have multiplicity greater than 1");
        }
        /// <summary>
        /// Add the rel property induced by the specified relationship, (if the target
        /// end has a multiplicity of one)
        /// We only keep track of rel-properties that are "interesting" 
        /// </summary>
        /// <param name="associationType">the association relationship</param>
        /// <param name="fromEnd">source end of the relationship traversal</param>
        /// <param name="toEnd">target end of the traversal</param>
        private void AddRelProperty(
            AssociationType associationType,
            AssociationEndMember fromEnd, AssociationEndMember toEnd)
        {
            if (toEnd.RelationshipMultiplicity
                == RelationshipMultiplicity.Many)
            {
                return;
            }
            var prop = new RelProperty(associationType, fromEnd, toEnd);
            if (_interestingRelProperties == null
                ||
                !_interestingRelProperties.Contains(prop))
            {
                return;
            }

            var entityType = ((RefType)fromEnd.TypeUsage.EdmType).ElementType;
            List<RelProperty> propList;
            if (!_relPropertyMap.TryGetValue(entityType, out propList))
            {
                propList = new List<RelProperty>();
                _relPropertyMap[entityType] = propList;
            }
            propList.Add(prop);
        }
		public static AssociationEndMember GetOtherAssociationEnd(
				this ObjectStateEntry entry, AssociationEndMember end)
		{
			end.ValidateBelongsTo(entry);
			AssociationEndMember[] ends = entry.GetAssociationEnds();
			if (ends[0] == end)
			{
				return ends[1];
			}
			return ends[0];
		}
 internal string GetNavigationPropertyName(AssociationEndMember toEnd, string storeTableName)
 {
     if (this.Service != null)
     {
         return toEnd.RelationshipMultiplicity == RelationshipMultiplicity.Many ?
             this.Service.Pluralize(storeTableName) : this.Service.Singularize(storeTableName);
     }
     else
     {
         return storeTableName;
     }
 }
		public static NavigationProperty GetNavigationProperty(this ObjectStateEntry entry, AssociationEndMember end)
		{
			end.ValidateBelongsTo(entry);

			var otherEnd = entry.GetOtherAssociationEnd(end);
			var relationshipType = entry.EntitySet.ElementType;

            EntityType elementType = GetInheritedEntityTypeByEntityName(entry, end.Name);
		    NavigationProperty property =
		        elementType.NavigationProperties.SingleOrDefault(p => p.RelationshipType == relationshipType &&
		                                                              p.FromEndMember == end && p.ToEndMember == otherEnd);
		    return property;
		}
		public static EntityKey GetEndEntityKey(this ObjectStateEntry entry, AssociationEndMember end)
		{
			end.ValidateBelongsTo(entry);

			AssociationEndMember[] ends = entry.GetAssociationEnds();

			if (ends[0] == end)
			{
				return entry.UsableValues()[0] as EntityKey;
			}

			return entry.UsableValues()[1] as EntityKey;
		}
Exemple #7
0
 internal WithRelationship(AssociationSet associationSet,
                           AssociationEndMember fromEnd,
                           EntityType fromEndEntityType,
                           AssociationEndMember toEnd,
                           EntityType toEndEntityType,
                           IEnumerable<MemberPath> toEndEntityKeyMemberPaths)
 {
     m_associationSet = associationSet;
     m_fromEnd = fromEnd;
     m_fromEndEntityType = fromEndEntityType;
     m_toEnd = toEnd;
     m_toEndEntityType = toEndEntityType;
     m_toEndEntitySet = MetadataHelper.GetEntitySetAtEnd(associationSet, toEnd);
     m_toEndEntityKeyMemberPaths = toEndEntityKeyMemberPaths;
 }
 private void CreateModelNavigationProperty(LoadMethodSessionState session, AssociationEndMember from, AssociationEndMember to)
 {
     EntityType entityType = (EntityType)((RefType)from.TypeUsage.EdmType).ElementType;
     UniqueIdentifierService usedMemberNames = new UniqueIdentifierService(false);
     LoadNameLookupWithUsedMemberNames(entityType, usedMemberNames);
     string name = CreateModelName(this._pluralizationServiceHandler.GetNavigationPropertyName(to, to.Name), usedMemberNames);
     NavigationProperty navigationProperty = new NavigationProperty(name, to.TypeUsage);
     navigationProperty.RelationshipType = (AssociationType)to.DeclaringType;
     navigationProperty.ToEndMember = to;
     navigationProperty.FromEndMember = from;
     entityType.AddMember(navigationProperty);
 }
 private AssociationEndMember CreateAssociationEndMember(LoadMethodSessionState session, AssociationEndMember storeEndMember, KeyValuePair<string, RelationshipMultiplicity> endMultiplicityOverride,  UniqueIdentifierService usedEndMemberNames)
 {
     RelationshipMultiplicity multiplicity = storeEndMember.RelationshipMultiplicity;
     if (endMultiplicityOverride.Key != null && endMultiplicityOverride.Key == storeEndMember.Name)
     {
         multiplicity = endMultiplicityOverride.Value;
     }
     return CreateAssociationEndMember(session, storeEndMember, usedEndMemberNames, multiplicity, storeEndMember.DeleteBehavior);
 }
 /// <summary>
 /// Constrcut a new AssociationEnd member mapping metadata object
 /// </summary>
 /// <param name="edmAssociationEnd"></param>
 /// <param name="clrAssociationEnd"></param>
 internal ObjectAssociationEndMapping(AssociationEndMember edmAssociationEnd, AssociationEndMember clrAssociationEnd)
     : base(edmAssociationEnd, clrAssociationEnd)
 {
 }
        // requires: IsForeignKeySuperSetOfPrimaryKeyInChildTable() is false
        // and primaryKeys of ChildTable are not mapped in cell. cell
        // corresponds to an association set. parentSet is the set
        // corresponding to the end that we are looking at
        // effects: Checks if the constraint is correctly maintained in
        // C-space via an association set (being a subset of the
        // corresponding entitySet)
        private bool CheckConstraintWhenOnlyParentMapped(Cell cell, EntitySet parentSet, AssociationSet assocSet, AssociationEndMember endMember,
                                                         QueryRewriter childRewriter, QueryRewriter parentRewriter,
                                                         ConfigViewGenerator config)
        {

            ViewgenContext childContext = childRewriter.ViewgenContext;
            ViewgenContext parentContext = parentRewriter.ViewgenContext;

            CellTreeNode pNode = parentRewriter.BasicView;
            Debug.Assert(pNode != null);

            RoleBoolean endRoleBoolean = new RoleBoolean(assocSet.AssociationSetEnds[endMember.Name]);
            // use query in pNode as a factory to create a bool expression for the endRoleBoolean
            BoolExpression endCondition = pNode.RightFragmentQuery.Condition.Create(endRoleBoolean);
            FragmentQuery cNodeQuery = FragmentQuery.Create(pNode.RightFragmentQuery.Attributes, endCondition);

            FragmentQueryProcessor qp = FragmentQueryProcessor.Merge(childContext.RightFragmentQP, parentContext.RightFragmentQP);
            bool cImpliesP = qp.IsContainedIn(cNodeQuery, pNode.RightFragmentQuery);
            return cImpliesP;
        }
 protected virtual void Visit(AssociationEndMember associationEndMember)
 {
     Visit(associationEndMember.TypeUsage);
 }
 private CodeTypeOfExpression GetEndTypeCodeExpression(AssociationEndMember end)
 {
     return new CodeTypeOfExpression(Generator.GetFullyQualifiedTypeReference(((RefType)end.TypeUsage.EdmType).ElementType));
 }
        // requires: IsForeignKeySuperSetOfPrimaryKeyInChildTable() is false
        // and primaryKeys of ChildTable are not mapped in cell. cell
        // corresponds to an association set. parentSet is the set
        // corresponding to the end that we are looking at
        // effects: Checks if the constraint is correctly maintained in
        // C-space via an association set (being a subset of the
        // corresponding entitySet)
        private static bool CheckConstraintWhenOnlyParentMapped(
            AssociationSet assocSet, AssociationEndMember endMember,
            QueryRewriter childRewriter, QueryRewriter parentRewriter)
        {
            var childContext = childRewriter.ViewgenContext;
            var parentContext = parentRewriter.ViewgenContext;

            var pNode = parentRewriter.BasicView;
            Debug.Assert(pNode != null);

            var endRoleBoolean = new RoleBoolean(assocSet.AssociationSetEnds[endMember.Name]);
            // use query in pNode as a factory to create a bool expression for the endRoleBoolean
            var endCondition = pNode.RightFragmentQuery.Condition.Create(endRoleBoolean);
            var cNodeQuery = FragmentQuery.Create(pNode.RightFragmentQuery.Attributes, endCondition);

            var qp = FragmentQueryProcessor.Merge(childContext.RightFragmentQP, parentContext.RightFragmentQP);
            var cImpliesP = qp.IsContainedIn(cNodeQuery, pNode.RightFragmentQuery);
            return cImpliesP;
        }
        /// <summary>
        /// Determines whether the specified { from, to } relationship end pairing represents a navigation that is
        /// valid for a relationship span sourced by an instance of the specified entity type.
        /// </summary>
        /// <param name="compareType">The Entity type which valid 'from' ends must reference (or a supertype of that Entity type)</param>
        /// <param name="associationType">The Association type to consider.</param>
        /// <param name="fromEnd">The candidate 'from' end, which will be checked based on the Entity type it references</param>
        /// <param name="toEnd">The candidate 'to' end, which will be checked base on the upper bound of its multiplicity</param>
        /// <returns>
        ///     <c>True</c> if the end pairing represents a valid navigation from an instance of the specified entity type
        ///     to an association end with a multiplicity upper bound of at most 1; otherwise <c>false</c>
        /// </returns>
        private static bool IsValidRelationshipSpan(EntityType compareType, AssociationType associationType, AssociationEndMember fromEnd, AssociationEndMember toEnd)
        {
            // Only a relationship end with a multiplicity of AT MOST one may be
            // considered as the 'to' end, so that the cardinality of the result
            // of the relationship span has an upper bound of 1. 
            // Therefore ends with RelationshipMultiplicity of EITHER One OR ZeroOrOne
            // are the only ends that should be considered as target ends.
            // Note that a relationship span can be sourced by an Entity that is of the same type
            // as the Entity type referenced by the 'from' end OR any type in the same branch of 
            // the type hierarchy.
            //
            // For example, in the following hierarchy:
            //
            // A  (*<-->?) AOwner
            // |_B  (*<-->1) BOwner
            // |_A1  (*<-->?) A1Owner
            //   |_A2
            //     |_A3_1  (1<-->?) A3_1Owner
            //     |_A3_2  (*<-->1) A3_2Owner
            //
            // An instance of 'A' would need ALL the 'AOwner', 'BOwner', 'A1Owner', 'A3_1Owner' and 'A3_2Owner' ends
            // spanned in because an instance of 'A' could actually be an instance of A, B, A1, A2, A3_1 or A3_2. 
            // An instance of 'B' would only need 'AOwner' and 'BOwner' spanned in.
            // An instance of A2 would need 'AOwner', 'A1Owner', 'A3_1Owner' and 'A3_2Owner' spanned in.
            // An instance of A3_1 would only need 'AOwner', 'A1Owner' and 'A3_1Owner' spanned in.
            //
            // In general, the rule for relationship span is:
            // - 'To' end cardinality AT MOST one
            //   AND
            //   - Referenced Entity type of 'From' end is equal to instance Entity type
            //     OR
            //   - Referenced Entity type of 'From' end is a supertype of instance Entity type
            //     OR
            //   - Referenced Entity type of 'From' end is a subtype of instance Entity type
            //     (this follows from the fact that an instance of 'A' may be an instance of any of its derived types.
            //      Navigation for a subtype relationship will return null if the Entity instance navigation source
            //      is not actually of the required subtype).
            //
            if(!associationType.IsForeignKey &&
               (RelationshipMultiplicity.One == toEnd.RelationshipMultiplicity ||
                RelationshipMultiplicity.ZeroOrOne == toEnd.RelationshipMultiplicity))
            {
                EntityType fromEntityType = (EntityType)((RefType)fromEnd.TypeUsage.EdmType).ElementType;
                return (ObjectSpanRewriter.EntityTypeEquals(compareType, fromEntityType) ||
                        TypeSemantics.IsSubTypeOf(compareType, fromEntityType) ||
                        TypeSemantics.IsSubTypeOf(fromEntityType, compareType));
            }

            return false;
        }
 // effects : Return the slot numbers for members in Cell Query that 
 //           represent the association end member passed in.
 internal List<int> GetAssociationEndSlots(AssociationEndMember endMember)
 {
     var slotIndexes = new List<int>();
     Debug.Assert(Extent is AssociationSet);
     for (var i = 0; i < m_projectedSlots.Length; i++)
     {
         var slot = m_projectedSlots[i] as MemberProjectedSlot;
         if (slot != null
             && slot.MemberPath.RootEdmMember.Equals(endMember))
         {
             slotIndexes.Add(i);
         }
     }
     return slotIndexes;
 }
        /// <summary>
        /// True if the specified association end is the principal in an identifying relationship.
        /// or if the association end has cascade delete defined.
        /// </summary>
        public bool IsCascadeDeletePrincipal(AssociationEndMember associationEnd)
        {
            if (associationEnd == null)
            {
                throw new ArgumentNullException("associationEnd");
            }

            return associationEnd.DeleteBehavior == OperationAction.Cascade || IsPrincipalEndOfIdentifyingRelationship(associationEnd);
        }
        private bool CreateReferentialConstraint(LoadMethodSessionState session,
            AssociationType association,
            AssociationEndMember pkEnd,
            AssociationEndMember fkEnd,
            List<RelationshipDetailsRow> columns,
            List<EdmSchemaError> errors)
        {
            EdmProperty[] fromProperties = new EdmProperty[columns.Count];
            EdmProperty[] toProperties = new EdmProperty[columns.Count];
            EntityType pkEntityType = session.RelationshipEndTypeLookup[pkEnd];
            EntityType fkEntityType = session.RelationshipEndTypeLookup[fkEnd];
            for (int index = 0; index < columns.Count; index++)
            {
                EdmProperty property;

                if(!pkEntityType.Properties.TryGetValue(columns[index].PKColumn, false, out property))
                {
                    errors.Add(
                        new EdmSchemaError(
                          Strings.AssociationMissingKeyColumn(
                            pkEntityType.Name,
                            fkEntityType.Name,
                            pkEntityType.Name + "." + columns[index].PKColumn),
                          (int)ModelBuilderErrorCode.AssociationMissingKeyColumn,
                          EdmSchemaErrorSeverity.Warning));
                    return false;
                }
                fromProperties[index] = property;

                if(!fkEntityType.Properties.TryGetValue(columns[index].FKColumn, false, out property))
                {
                    errors.Add(
                        new EdmSchemaError(
                        Strings.AssociationMissingKeyColumn(
                            pkEntityType.Name,
                            fkEntityType.Name,
                            fkEntityType.Name + "." + columns[index].FKColumn),
                            (int)ModelBuilderErrorCode.AssociationMissingKeyColumn,
                        EdmSchemaErrorSeverity.Warning));
                    return false;
                }
                toProperties[index] = property;
            }

            ReferentialConstraint constraint = new ReferentialConstraint(pkEnd,
                fkEnd,
                fromProperties,
                toProperties);

            association.AddReferentialConstraint(constraint);
            return true;
        }
        protected override void Visit(AssociationEndMember associationEndMember)
        {
            int index;
            if (!this.AddObjectToSeenListAndHashBuilder(associationEndMember, out index))
            {
                return;
            }

            this.AddObjectStartDumpToHashBuilder(associationEndMember, index);

            #region Inner data visit
            this.AddObjectContentToHashBuilder(associationEndMember.DeleteBehavior);
            this.AddObjectContentToHashBuilder(associationEndMember.Identity);
            // Name is covered by Identity
            this.AddObjectContentToHashBuilder(associationEndMember.IsStoreGeneratedComputed);
            this.AddObjectContentToHashBuilder(associationEndMember.IsStoreGeneratedIdentity);
            this.AddObjectContentToHashBuilder(associationEndMember.RelationshipMultiplicity);

            base.Visit(associationEndMember);

            #endregion

            this.AddObjectEndDumpToHashBuilder();
        }
            private static void ProcessReferenceCandidate(
                EntityKey source, 
                HashSet<IEntityStateEntry> stateEntries, 
                Dictionary<AssociationEndMember, IEntityStateEntry> currentReferenceEnd, 
                Dictionary<AssociationEndMember, IEntityStateEntry> originalReferenceEnd, 
                AssociationEndMember endMember,
                IEntityStateEntry candidateEntry)
            {
                Func<DbDataRecord, int, EntityKey> getEntityKey = (record, ordinal) => (EntityKey)record[ordinal];
                Action<DbDataRecord, Action<IEntityStateEntry>> findMatch = (record, registerTarget) =>
                {
                    // find the end corresponding to the 'to' end
                    int toOrdinal = record.GetOrdinal(endMember.Name);
                    Debug.Assert(-1 != toOrdinal, "to end of relationship doesn't exist in record");

                    // the 'from' end must be the other end
                    int fromOrdinal = 0 == toOrdinal ? 1 : 0;

                    if (getEntityKey(record, fromOrdinal) == source)
                    {
                        stateEntries.Add(candidateEntry);
                        registerTarget(candidateEntry);
                    }
                };

                switch (candidateEntry.State)
                {
                    case EntityState.Unchanged:
                        findMatch(
                            candidateEntry.CurrentValues,
                            (target) =>
                            {
                                currentReferenceEnd.Add(endMember, target);
                                originalReferenceEnd.Add(endMember, target);
                            });
                        break;
                    case EntityState.Added:
                        findMatch(
                            candidateEntry.CurrentValues,
                            (target) => currentReferenceEnd.Add(endMember, target));
                        break;
                    case EntityState.Deleted:
                        findMatch(
                            candidateEntry.OriginalValues,
                            (target) => originalReferenceEnd.Add(endMember, target));
                        break;
                    default:
                        break;
                }
            }
        private AssociationEndMember CreateAssociationEndMember(LoadMethodSessionState session, AssociationEndMember storeEndMember, UniqueIdentifierService usedEndMemberNames, RelationshipMultiplicity multiplicityOverride, OperationAction deleteBehaviorOverride)
        {
            Debug.Assert(storeEndMember.TypeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.RefType, "The type is not a ref type");
            Debug.Assert(((RefType)storeEndMember.TypeUsage.EdmType).ElementType.BuiltInTypeKind == BuiltInTypeKind.EntityType, "the ref is not holding on to an EntityType");
            
            EntityType storeEntityType = ((EntityType)((RefType)storeEndMember.TypeUsage.EdmType).ElementType);
            EntityType modelEntityType = session.MappingLookups.StoreEntityTypeToModelEntityType[storeEntityType];

            string name = CreateModelName(storeEndMember.Name, usedEndMemberNames);
            AssociationEndMember end = new AssociationEndMember(name, modelEntityType.GetReferenceType(), multiplicityOverride);
            end.DeleteBehavior = deleteBehaviorOverride;
            return end;            
        }
        // effects: Given the foreign key constraint, checks if the
        // constraint.ParentColumns are mapped to the entity set E'e keys in
        // C-space where E corresponds to the entity set corresponding to end
        // Returns true iff such a mapping exists in cell
        private bool CheckParentColumnsForForeignKey(
            Cell cell, IEnumerable<Cell> cells, AssociationEndMember parentEnd, ref List<ErrorLog.Record> errorList)
        {
            // The child columns are mapped to some end of cell.CQuery.Extent. ParentColumns
            // must correspond to the EntitySet for this end
            var relationSet = (AssociationSet)cell.CQuery.Extent;
            var endSet = MetadataHelper.GetEntitySetAtEnd(relationSet, parentEnd);

            // Check if the ParentColumns are mapped to endSet's keys

            // Find the entity set that they map to - if any
            var entitySet = FindEntitySetForColumnsMappedToEntityKeys(cells, ParentColumns);
            if (entitySet == null
                || endSet.Equals(entitySet) == false)
            {
                if (errorList == null) //lazily initialize only if there is an error
                {
                    errorList = new List<ErrorLog.Record>();
                }

                // childColumns are mapped to parentEnd but ParentColumns are not mapped to the end
                // corresponding to the parentEnd -- this is an error
                var message = Strings.ViewGen_Foreign_Key_ParentTable_NotMappedToEnd(
                    ToUserString(), ChildTable.Name,
                    cell.CQuery.Extent.Name, parentEnd.Name, ParentTable.Name, endSet.Name);
                var record = new ErrorLog.Record(ViewGenErrorCode.ForeignKeyParentTableNotMappedToEnd, message, cell, String.Empty);
                errorList.Add(record);
                return false;
            }
            return true;
        }
        private bool TryGetNavigationSource(AssociationEndMember wasSourceNowTargetEnd, out DbExpression source)
        {
            source = null;

            NavigationInfo info = null;
            if (_navSources.Count > 0)
            {
                info = _navSources.Peek();
                if (info != null && !object.ReferenceEquals(wasSourceNowTargetEnd, info.SourceEnd))
                {
                    info = null;
                }
            }

            if (info != null)
            {
                source = info.SourceVariable;
                info.InUse = true;
                return true;
            }
            else
            {
                return false;
            }
        }
 private AssociationEndMember CreateAssociationEnd(LoadMethodSessionState session, 
     EntityType type, 
     RelationshipMultiplicity multiplicity,
     UniqueIdentifierService usedEndNames,
     OperationAction deleteAction
     )
 {
     string role = usedEndNames.AdjustIdentifier(type.Name);
     RefType refType = type.GetReferenceType();
     AssociationEndMember end = new AssociationEndMember(role, refType, multiplicity);
     end.DeleteBehavior = deleteAction;
     session.RelationshipEndTypeLookup.Add(end, type);
     return end;
 }
            public NavigationInfo(DbRelationshipNavigationExpression originalNavigation, DbRelationshipNavigationExpression rewrittenNavigation)
            {
                Debug.Assert(originalNavigation != null, "originalNavigation cannot be null");
                Debug.Assert(rewrittenNavigation != null, "rewrittenNavigation cannot be null");

                this._original = originalNavigation;
                this._rewritten = rewrittenNavigation;
                this._sourceEnd = (AssociationEndMember)originalNavigation.NavigateFrom;
                this._sourceRef = (DbVariableReferenceExpression)rewrittenNavigation.NavigationSource;
                this._source = originalNavigation.NavigationSource;
            }
 /// <summary>
 /// Initializes a new instance of AssocationSetEnd
 /// </summary>
 /// <param name="entitySet">Entity set that this end refers to</param>
 /// <param name="parentSet">The association set which this belongs to</param>
 /// <param name="endMember">The end member of the association set which this is an instance of</param>
 /// <exception cref="System.ArgumentNullException">Thrown if either the role,entitySet, parentSet or endMember arguments are null </exception>
 internal AssociationSetEnd(EntitySet entitySet, AssociationSet parentSet, AssociationEndMember endMember)
 {
     _entitySet = EntityUtil.GenericCheckArgumentNull(entitySet, "entitySet");
     _parentSet = EntityUtil.GenericCheckArgumentNull(parentSet, "parentSet");
     _endMember = EntityUtil.GenericCheckArgumentNull(endMember, "endMember");
 }
        /// <summary>
        /// True if the specified association end is the principal end in an identifying relationship.
        /// In order to be an identifying relationship, the association must have a referential constraint where all of the dependent properties are part of the dependent type's primary key.
        /// </summary>
        public bool IsPrincipalEndOfIdentifyingRelationship(AssociationEndMember associationEnd)
        {
            if (associationEnd == null)
            {
                throw new ArgumentNullException("associationEnd");
            }

            ReferentialConstraint refConstraint = ((AssociationType)associationEnd.DeclaringType).ReferentialConstraints.Where(rc => rc.FromRole == associationEnd).SingleOrDefault();
            if (refConstraint != null)
            {
                EntityType entity = refConstraint.ToRole.GetEntityType();
                return !refConstraint.ToProperties.Where(tp => !entity.KeyMembers.Contains(tp)).Any();
            }
            return false;
        }
        // Helper method to determine if the specified entityKey is in the given role and AssociationSet in this relationship entry
        internal bool IsSameAssociationSetAndRole(AssociationSet associationSet, AssociationEndMember associationMember, EntityKey entityKey)
        {
            Debug.Assert(associationSet.ElementType.AssociationEndMembers[0].Name == associationMember.Name ||
                         associationSet.ElementType.AssociationEndMembers[1].Name == associationMember.Name,
                         "Expected associationMember to be one of the ends of the specified associationSet.");

            if (!Object.ReferenceEquals(_entitySet, associationSet))
            {
                return false;
            }

            // Find the end of the relationship that corresponds to the associationMember and see if it matches the EntityKey we are looking for
            if (_relationshipWrapper.AssociationSet.ElementType.AssociationEndMembers[0].Name == associationMember.Name)
            {
                return entityKey == Key0;
            }
            else
            {
                return entityKey == Key1;
            }
        }
        // requires: IsForeignKeySuperSetOfPrimaryKeyInChildTable() is false
        // effects: Given that both the ChildColumns in this and the
        // primaryKey of ChildTable are mapped. Return true iff no error occurred
        private bool CheckConstraintWhenParentChildMapped(
            Cell cell, ErrorLog errorLog,
            AssociationEndMember parentEnd, ConfigViewGenerator config)
        {
            var ok = true;

            // The foreign key constraint has been mapped to a
            // relationship. Check if the multiplicities are consistent
            // If all columns in the child table (corresponding to
            // the constraint) are nullable, the parent end can be
            // 0..1 or 1..1. Else if must be 1..1
            if (parentEnd.RelationshipMultiplicity
                == RelationshipMultiplicity.Many)
            {
                // Parent should at most one since we are talking
                // about foreign keys here
                var message = Strings.ViewGen_Foreign_Key_UpperBound_MustBeOne(
                    ToUserString(),
                    cell.CQuery.Extent.Name, parentEnd.Name);
                var record = new ErrorLog.Record(ViewGenErrorCode.ForeignKeyUpperBoundMustBeOne, message, cell, String.Empty);
                errorLog.AddEntry(record);
                ok = false;
            }

            if (MemberPath.AreAllMembersNullable(ChildColumns) == false
                && parentEnd.RelationshipMultiplicity != RelationshipMultiplicity.One)
            {
                // Some column in the constraint in the child table
                // is non-nullable and lower bound is not 1
                var message = Strings.ViewGen_Foreign_Key_LowerBound_MustBeOne(
                    ToUserString(),
                    cell.CQuery.Extent.Name, parentEnd.Name);
                var record = new ErrorLog.Record(ViewGenErrorCode.ForeignKeyLowerBoundMustBeOne, message, cell, String.Empty);
                errorLog.AddEntry(record);
                ok = false;
            }

            if (config.IsNormalTracing && ok)
            {
                Trace.WriteLine("Foreign key mapped to relationship " + cell.CQuery.Extent.Name);
            }
            return ok;
        }
 /// <summary>
 /// Initializes a new instance of AssocationSetEnd
 /// </summary>
 /// <param name="entitySet">Entity set that this end refers to</param>
 /// <param name="parentSet">The association set which this belongs to</param>
 /// <param name="endMember">The end member of the association set which this is an instance of</param>
 /// <exception cref="System.ArgumentNullException">Thrown if either the role,entitySet, parentSet or endMember arguments are null </exception>
 internal AssociationSetEnd(EntitySet entitySet, AssociationSet parentSet, AssociationEndMember endMember)
 {
     _entitySet = EntityUtil.GenericCheckArgumentNull(entitySet, "entitySet");
     _parentSet = EntityUtil.GenericCheckArgumentNull(parentSet, "parentSet");
     _endMember = EntityUtil.GenericCheckArgumentNull(endMember, "endMember");
 }
 static private void AddEnd(ref Set<AssociationEndMember> set, AssociationEndMember element)
 {
     if (null == set)
     {
         set = new Set<AssociationEndMember>();
     }
     set.Add(element);
 }
        /// <summary>
        /// Initialize the end member if its not initialized already
        /// </summary>
        /// <param name="associationType"></param>
        /// <param name="end"></param>
        /// <param name="endMemberType"></param>
        private static AssociationEndMember InitializeAssociationEndMember(AssociationType associationType, Som.IRelationshipEnd end,
            EntityType endMemberType)
        {
            AssociationEndMember associationEnd;

            EdmMember member;
            // make sure that the end is not initialized as of yet
            if (!associationType.Members.TryGetValue(end.Name, false/*ignoreCase*/, out member))
            {
                // Create the end member and add the operations
                associationEnd = new AssociationEndMember(end.Name,
                                                          endMemberType.GetReferenceType(),
                                                          end.Multiplicity.Value);
                associationType.AddKeyMember(associationEnd);
            }
            else
            {
                associationEnd = (AssociationEndMember)member;
            }

            //Extract the optional Documentation
            Som.RelationshipEnd relationshipEnd = end as Som.RelationshipEnd;

            if (relationshipEnd != null && (relationshipEnd.Documentation != null))
            {
                associationEnd.Documentation = ConvertToDocumentation(relationshipEnd.Documentation);
            }

            return associationEnd;
        }