/// <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);
        }
示例#2
0
        // effects: Returns a key correspnding to all the fields in different
        // ends of relationtype prefixed with "prefix"
        internal static ExtentKey GetKeyForRelationType(MemberPath prefix, AssociationType relationType)
        {
            var keyFields = new List<MemberPath>();

            foreach (var endMember in relationType.AssociationEndMembers)
            {
                var endPrefix = new MemberPath(prefix, endMember);
                var entityType = MetadataHelper.GetEntityTypeForEnd(endMember);
                var primaryKey = GetPrimaryKeyForEntityType(endPrefix, entityType);
                keyFields.AddRange(primaryKey.KeyFields);
            }
            var key = new ExtentKey(keyFields);
            return key;
        }
示例#3
0
        /// <summary>
        /// Load all relationships in this entity container
        /// </summary>
        /// <param name="entityContainer"></param>
        internal void LoadRelationships(md.EntityContainer entityContainer)
        {
            // Check to see if I've already loaded information for this entity container
            if (m_entityContainerMap.ContainsKey(entityContainer))
            {
                return;
            }

            // Load all relationships from this entitycontainer
            foreach (md.EntitySetBase e in entityContainer.BaseEntitySets)
            {
                md.RelationshipSet relationshipSet = e as md.RelationshipSet;
                if (relationshipSet == null)
                {
                    continue;
                }

                // Relationship sets can only contain relationships
                md.RelationshipType relationshipType = (md.RelationshipType)relationshipSet.ElementType;
                md.AssociationType  assocType        = relationshipType as md.AssociationType;

                //
                // Handle only binary Association relationships for now
                //
                if (null == assocType || !IsBinary(relationshipType))
                {
                    continue;
                }

                foreach (md.ReferentialConstraint constraint in assocType.ReferentialConstraints)
                {
                    List <ForeignKeyConstraint> fkConstraintList;
                    ForeignKeyConstraint        fkConstraint = new ForeignKeyConstraint(relationshipType, relationshipSet, constraint);
                    if (!m_parentChildRelationships.TryGetValue(fkConstraint.Pair, out fkConstraintList))
                    {
                        fkConstraintList = new List <ForeignKeyConstraint>();
                        m_parentChildRelationships[fkConstraint.Pair] = fkConstraintList;
                    }
                    //
                    // Theoretically, we can have more than one fk constraint between
                    // the 2 tables (though, it is unlikely)
                    //
                    fkConstraintList.Add(fkConstraint);
                }
            }

            // Mark this entity container as already loaded
            m_entityContainerMap[entityContainer] = entityContainer;
        }
示例#4
0
        private void CreateRelationships()
        {
            if (SessionData.ConventionBasedRelationshipsAreLoaded)
            {
                return;
            }


            SessionData.ConventionBasedRelationshipsAreLoaded = true;

            // find all the relationships
            foreach (AssociationType cspaceAssociation in SessionData.EdmItemCollection.GetItems <AssociationType>())
            {
                Debug.Assert(cspaceAssociation.RelationshipEndMembers.Count == 2, "Relationships are assumed to have exactly two ends");

                if (SessionData.CspaceToOspace.ContainsKey(cspaceAssociation))
                {
                    // don't try to load relationships that we already know about
                    continue;
                }

                EdmType[] ospaceEndTypes = new EdmType[2];
                if (SessionData.CspaceToOspace.TryGetValue(GetRelationshipEndType(cspaceAssociation.RelationshipEndMembers[0]), out ospaceEndTypes[0]) &&
                    SessionData.CspaceToOspace.TryGetValue(GetRelationshipEndType(cspaceAssociation.RelationshipEndMembers[1]), out ospaceEndTypes[1]))
                {
                    Debug.Assert(ospaceEndTypes[0] is StructuralType);
                    Debug.Assert(ospaceEndTypes[1] is StructuralType);

                    // if we can find both ends of the relationship, then create it

                    AssociationType ospaceAssociation = new AssociationType(cspaceAssociation.Name, cspaceAssociation.NamespaceName, cspaceAssociation.IsForeignKey, DataSpace.OSpace);
                    for (int i = 0; i < cspaceAssociation.RelationshipEndMembers.Count; i++)
                    {
                        EntityType            ospaceEndType = (EntityType)ospaceEndTypes[i];
                        RelationshipEndMember cspaceEnd     = cspaceAssociation.RelationshipEndMembers[i];

                        ospaceAssociation.AddKeyMember(new AssociationEndMember(cspaceEnd.Name, ospaceEndType.GetReferenceType(), cspaceEnd.RelationshipMultiplicity));
                    }
                    CacheEntry.TypesInAssembly.Add(ospaceAssociation);
                    SessionData.TypesInLoading.Add(ospaceAssociation.FullName, ospaceAssociation);
                    SessionData.CspaceToOspace.Add(cspaceAssociation, ospaceAssociation);
                }
            }
        }
示例#5
0
 internal static AssociationEndMember GetEndThatShouldBeMappedToKey(AssociationType associationType)
 {
     //For 1:* and 1:0..1 associations, the end other than 1 i.e. either * or 0..1 ends need to be
     //mapped to key columns
     if (associationType.AssociationEndMembers.Any(it =>
                                                   it.RelationshipMultiplicity.Equals(RelationshipMultiplicity.One)))
     {
         {
             return(associationType.AssociationEndMembers.SingleOrDefault(it =>
                                                                          ((it.RelationshipMultiplicity.Equals(RelationshipMultiplicity.Many)) ||
                                                                           (it.RelationshipMultiplicity.Equals(RelationshipMultiplicity.ZeroOrOne)))));
         }
     }
     //For 0..1:* associations, * end must be mapped to key.
     else if (associationType.AssociationEndMembers.Any(it =>
                                                        (it.RelationshipMultiplicity.Equals(RelationshipMultiplicity.ZeroOrOne))))
     {
         {
             return(associationType.AssociationEndMembers.SingleOrDefault(it =>
                                                                          ((it.RelationshipMultiplicity.Equals(RelationshipMultiplicity.Many)))));
         }
     }
     return(null);
 }
 public AssociationTypeEmitter(ClientApiGenerator generator, AssociationType associationType)
     : base(generator, associationType)
 {
 }
        private string GetAssociationCreateScript(AssociationType a)
        {
            StringBuilder sql = new StringBuilder();
            StringBuilder keySql = new StringBuilder();

            if (a.IsForeignKey)
            {
                EntityType childType = (EntityType)a.ReferentialConstraints[0].ToProperties[0].DeclaringType;
                EntityType parentType = (EntityType)a.ReferentialConstraints[0].FromProperties[0].DeclaringType;

                sql.AppendLine(String.Format(
                    "ALTER TABLE `{0}` ADD CONSTRAINT {1}", childType.Name, a.Name));
                sql.Append("\t FOREIGN KEY (");
                string delimiter = "";
                foreach (EdmProperty p in a.ReferentialConstraints[0].ToProperties)
                {
                    EdmMember member;
                    if (!childType.KeyMembers.TryGetValue(p.Name, false, out member))
                        keySql.AppendLine(String.Format(
                            "ALTER TABLE `{0}` ADD KEY (`{1}`);", childType.Name, p.Name));
                    sql.AppendFormat("{0}{1}", delimiter, p.Name);
                    delimiter = ", ";
                }
                sql.AppendLine(")");
                delimiter = "";
                sql.Append(String.Format("\tREFERENCES {0} (", parentType.Name));
                foreach (EdmProperty p in a.ReferentialConstraints[0].FromProperties)
                {
                    EdmMember member;
                    if (!parentType.KeyMembers.TryGetValue(p.Name, false, out member))
                        keySql.AppendLine(String.Format(
                            "ALTER TABLE `{0}` ADD KEY (`{1}`);", parentType.Name, p.Name));
                    sql.AppendFormat("{0}{1}", delimiter, p.Name);
                    delimiter = ", ";
                }
                sql.AppendLine(");");
                sql.AppendLine();
            }

            keySql.Append(sql.ToString());
            return keySql.ToString();
        }
示例#8
0
    private string GetAssociationCreateScript(AssociationType a)
    {
      StringBuilder sql = new StringBuilder();
      StringBuilder keySql = new StringBuilder();

      if (a.IsForeignKey)
      {
        EntityType childType = (EntityType)a.ReferentialConstraints[0].ToProperties[0].DeclaringType;
        EntityType parentType = (EntityType)a.ReferentialConstraints[0].FromProperties[0].DeclaringType;
		string fkName = a.Name;
        if (fkName.Length > 64)
        {
          fkName = "FK_" + Guid.NewGuid().ToString().Replace("-", "");
        }
        sql.AppendLine(String.Format(
            "ALTER TABLE `{0}` ADD CONSTRAINT {1}", _pluralizedNames[ childType.Name ], fkName));
        sql.Append("\t FOREIGN KEY (");
        string delimiter = "";
        foreach (EdmProperty p in a.ReferentialConstraints[0].ToProperties)
        {
          EdmMember member;
          if (!childType.KeyMembers.TryGetValue(p.Name, false, out member))
            keySql.AppendLine(String.Format(
                "ALTER TABLE `{0}` ADD KEY (`{1}`);", _pluralizedNames[childType.Name], p.Name));
          sql.AppendFormat("{0}{1}", delimiter, p.Name);          
          delimiter = ", ";
        }
        sql.AppendLine(")");        
        delimiter = "";
        sql.Append(String.Format("\tREFERENCES {0} (", _pluralizedNames[parentType.Name]));
        foreach (EdmProperty p in a.ReferentialConstraints[0].FromProperties)
        {
          EdmMember member;
          if (!parentType.KeyMembers.TryGetValue(p.Name, false, out member))
            keySql.AppendLine(String.Format(
                "ALTER TABLE `{0}` ADD KEY (`{1}`);", _pluralizedNames[parentType.Name], p.Name));
          sql.AppendFormat("{0}{1}", delimiter, p.Name);
          delimiter = ", ";
        }
        sql.AppendLine(")");
        OperationAction oa = a.AssociationEndMembers[0].DeleteBehavior;
        sql.AppendLine(String.Format(" ON DELETE {0} ON UPDATE {1};",
          oa == OperationAction.None ? "NO ACTION" : oa.ToString(), "NO ACTION"));
        sql.AppendLine();
      }

      keySql.Append(sql.ToString());
      return keySql.ToString();
    }
        static internal bool IsFkPartiallyContainedInPK(AssociationType association, out string errorMessage)
        {
            ReferentialConstraint constraint = association.ReferentialConstraints[0];
            EntityType toType = (EntityType)constraint.ToProperties[0].DeclaringType;

            bool toPropertiesAreFullyContainedInPk = true;
            bool toPropertiesContainedAtLeastOnePK = false;

            foreach (EdmProperty edmProperty in constraint.ToProperties)
            {
                // check if there is at least one to property is not primary key
                toPropertiesAreFullyContainedInPk &= toType.KeyMembers.Contains(edmProperty);
                // check if there is one to property is primary key
                toPropertiesContainedAtLeastOnePK |= toType.KeyMembers.Contains(edmProperty); 
            }
            if (!toPropertiesAreFullyContainedInPk && toPropertiesContainedAtLeastOnePK)
            {
                string foreignKeys = MetadataUtil.MembersToCommaSeparatedString((System.Collections.IEnumerable)constraint.ToProperties);
                string primaryKeys = MetadataUtil.MembersToCommaSeparatedString((System.Collections.IEnumerable)toType.KeyMembers);
                errorMessage = Strings.UnsupportedForeignKeyPattern(association.Name, foreignKeys, primaryKeys, toType.Name);
                return true;
            }
            errorMessage = "";
            return false;
        }
        internal void ResolveNavigationProperty(StructuralType declaringType, PropertyInfo propertyInfo)
        {
            Debug.Assert(propertyInfo.IsDefined(typeof(EdmRelationshipNavigationPropertyAttribute), false), "The property must have navigation property defined");

            // EdmScalarPropertyAttribute, EdmComplexPropertyAttribute and EdmRelationshipNavigationPropertyAttribute
            // are all EdmPropertyAttributes that we need to process. If the current property is not an EdmPropertyAttribute
            // we will just ignore it and skip to the next property.
            object[] relationshipPropertyAttributes = propertyInfo.GetCustomAttributes(typeof(EdmRelationshipNavigationPropertyAttribute), false);

            Debug.Assert(relationshipPropertyAttributes.Length == 1, "There should be exactly one property for every navigation property");

            // The only valid return types from navigation properties are:
            //     (1) EntityType
            //     (2) CollectionType containing valid EntityType

            // If TryGetLoadedType returned false, it could mean that we couldn't validate any part of the type, or it could mean that it's a generic
            // where the main generic type was validated, but the generic type parameter was not. We can't tell the difference, so just fail
            // with the same error message in both cases. The user will have to figure out which part of the type is wrong.
            // We can't just rely on checking for a generic because it can lead to a scenario where we report that the type parameter is invalid
            // when really it's the main generic type. That is more confusing than reporting the full name and letting the user determine the problem.
            EdmType propertyType;

            if (!TryGetLoadedType(propertyInfo.PropertyType, out propertyType) || !(propertyType.BuiltInTypeKind == BuiltInTypeKind.EntityType || propertyType.BuiltInTypeKind == BuiltInTypeKind.CollectionType))
            {
                // Once an error is detected the property does not need to be validated further, just add to the errors
                // collection and continue with the next property. The failure will cause an exception to be thrown later during validation of all of the types.
                SessionData.EdmItemErrors.Add(new EdmItemError(System.Data.Entity.Strings.Validator_OSpace_InvalidNavPropReturnType(propertyInfo.Name, propertyInfo.DeclaringType.FullName, propertyInfo.PropertyType.FullName), null));
                return;
            }
            // else we have a valid EntityType or CollectionType that contains EntityType. ResolveNonSchemaType enforces that a collection type
            // must contain an EntityType, and if it doesn't, propertyType will be null here. If propertyType is EntityType or CollectionType we know it is valid

            // Expecting EdmRelationshipNavigationPropertyAttribute to have AllowMultiple=False, so only look at first element in the attribute array

            EdmRelationshipNavigationPropertyAttribute attribute = (EdmRelationshipNavigationPropertyAttribute)relationshipPropertyAttributes[0];

            EdmMember member = null;
            EdmType   type;

            if (SessionData.TypesInLoading.TryGetValue(attribute.RelationshipNamespaceName + "." + attribute.RelationshipName, out type) &&
                Helper.IsAssociationType(type))
            {
                AssociationType relationshipType = (AssociationType)type;
                if (relationshipType != null)
                {
                    // The return value of this property has been verified, so create the property now
                    NavigationProperty navigationProperty = new NavigationProperty(propertyInfo.Name, TypeUsage.Create(propertyType), propertyInfo);
                    navigationProperty.RelationshipType = relationshipType;
                    member = navigationProperty;

                    if (relationshipType.Members[0].Name == attribute.TargetRoleName)
                    {
                        navigationProperty.ToEndMember   = (RelationshipEndMember)relationshipType.Members[0];
                        navigationProperty.FromEndMember = (RelationshipEndMember)relationshipType.Members[1];
                    }
                    else if (relationshipType.Members[1].Name == attribute.TargetRoleName)
                    {
                        navigationProperty.ToEndMember   = (RelationshipEndMember)relationshipType.Members[1];
                        navigationProperty.FromEndMember = (RelationshipEndMember)relationshipType.Members[0];
                    }
                    else
                    {
                        SessionData.EdmItemErrors.Add(new EdmItemError(System.Data.Entity.Strings.TargetRoleNameInNavigationPropertyNotValid(
                                                                           propertyInfo.Name, propertyInfo.DeclaringType.FullName, attribute.TargetRoleName, attribute.RelationshipName), navigationProperty));
                        member = null;
                    }

                    if (member != null &&
                        ((RefType)navigationProperty.FromEndMember.TypeUsage.EdmType).ElementType.ClrType != declaringType.ClrType)
                    {
                        SessionData.EdmItemErrors.Add(new EdmItemError(System.Data.Entity.Strings.NavigationPropertyRelationshipEndTypeMismatch(
                                                                           declaringType.FullName,
                                                                           navigationProperty.Name,
                                                                           relationshipType.FullName,
                                                                           navigationProperty.FromEndMember.Name,
                                                                           ((RefType)navigationProperty.FromEndMember.TypeUsage.EdmType).ElementType.ClrType), navigationProperty));
                        member = null;
                    }
                }
            }
            else
            {
                SessionData.EdmItemErrors.Add(new EdmItemError(System.Data.Entity.Strings.RelationshipNameInNavigationPropertyNotValid(
                                                                   propertyInfo.Name, propertyInfo.DeclaringType.FullName, attribute.RelationshipName), declaringType));
            }

            if (member != null)
            {
                declaringType.AddMember(member);
            }
        }
示例#11
0
 /// <summary>
 /// Initializes a new instance of AssocationSet with the given name and the association type
 /// </summary>
 /// <param name="name">The name of the Assocation set</param>
 /// <param name="associationType">The association type of the entities that this associationship set type contains</param>
 internal AssociationSet(string name, AssociationType associationType)
     : base(name, null, null, null, associationType)
 {
 }
        private KeyValuePair<string, RelationshipMultiplicity> CreateEndMultiplicityOverride(LoadMethodSessionState session, AssociationType storeAssociation, AssociationType modelAssociation)
        {
            // does the store have any constraints
            if (storeAssociation.ReferentialConstraints.Count == 0)
            {
                return new KeyValuePair<string, RelationshipMultiplicity>();
            }

            ReferentialConstraint storeConstraint = storeAssociation.ReferentialConstraints[0];

            //For foreign key associations, having any nullable columns will imply 0..1
            //multiplicity, while for independent associations, all columns must be non-nullable for 
            //0..1 association.
            bool nullableColumnsImplyingOneToOneMultiplicity = false;
            if (this.GenerateForeignKeyProperties)
            {
                nullableColumnsImplyingOneToOneMultiplicity = storeConstraint.ToProperties.All(p => p.Nullable == false);
            }
            else
            {
                nullableColumnsImplyingOneToOneMultiplicity = storeConstraint.ToProperties.Any(p => p.Nullable == false);
            }

            if (storeConstraint.FromRole.RelationshipMultiplicity == RelationshipMultiplicity.ZeroOrOne &&
               storeConstraint.ToRole.RelationshipMultiplicity == RelationshipMultiplicity.Many &&
               nullableColumnsImplyingOneToOneMultiplicity)
            {
                return new KeyValuePair<string, RelationshipMultiplicity>(storeConstraint.FromRole.Name, RelationshipMultiplicity.One);
            }

            return new KeyValuePair<string, RelationshipMultiplicity>();
        }
        private AssociationSet CreateModelAssociationSet(LoadMethodSessionState session, OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsedAssociationSet)
        {
            // create the association
            string associationName = CreateModelName(collapsedAssociationSet.EntitySet.Name, session.UsedGlobalModelTypeNames);
            AssociationType association = new AssociationType(associationName,
                _namespaceName, false, DataSpace.CSpace);

            // create the association set
            string associationSetName = CreateModelName(collapsedAssociationSet.EntitySet.Name, session.UsedEntityContainerItemNames);
            AssociationSet set = new AssociationSet(associationSetName, association);
            
            // create the association and association set end members
            UniqueIdentifierService usedEndMemberNames = new UniqueIdentifierService(false);
            for(int i = 0; i < collapsedAssociationSet.AssociationSets.Count; i++)
            {
                AssociationSetEnd storeEnd;
                RelationshipMultiplicity multiplicity;
                OperationAction deleteBehavior;
                collapsedAssociationSet.GetStoreAssociationSetEnd(i, out storeEnd, out multiplicity, out deleteBehavior);
                AssociationEndMember end = CreateAssociationEndMember(session, storeEnd.CorrespondingAssociationEndMember, usedEndMemberNames, multiplicity, deleteBehavior);
                association.AddMember(end);

                EntitySet entitySet = session.MappingLookups.StoreEntitySetToModelEntitySet[storeEnd.EntitySet];
                AssociationSetEnd setEnd = new AssociationSetEnd(entitySet, set, end);
                set.AddAssociationSetEnd(setEnd);
                session.MappingLookups.StoreAssociationSetEndToModelAssociationSetEnd.Add(storeEnd, setEnd);
            }

            // don't need a referential constraint

            CreateModelNavigationProperties(session, association);

            collapsedAssociationSet.ModelAssociationSet = set;
           
            return set;
        }
        private static bool RequiresModelReferentialConstraint(AssociationType storeAssociation)
        {
            // does the store have any constraints
            if (storeAssociation.ReferentialConstraints.Count == 0)
            {
                return false;
            }

            ReferentialConstraint storeConstraint = storeAssociation.ReferentialConstraints[0];
            Debug.Assert(storeConstraint.FromProperties.Count == storeConstraint.ToProperties.Count, "FromProperties and ToProperties have different counts");
            Debug.Assert(storeConstraint.FromProperties.Count != 0, "No properties in the constraint, why does the constraint exist?");
            Debug.Assert(storeConstraint.ToProperties[0].DeclaringType.BuiltInTypeKind == BuiltInTypeKind.EntityType, "The property is not from an EntityType");

            EntityType toType = (EntityType)storeConstraint.ToProperties[0].DeclaringType;
            return RequiresModelReferentialConstraint(storeConstraint, toType);
        }
        protected override void Visit(AssociationType associationType)
        {
            int index;
            if (!this.AddObjectToSeenListAndHashBuilder(associationType, out index))
            {
                return;
            }

            this.AddObjectStartDumpToHashBuilder(associationType, index);

            #region Inner data visit
            this.AddObjectContentToHashBuilder(associationType.Abstract);
            this.AddObjectContentToHashBuilder(associationType.Identity);
            // FullName, Namespace, and Name are all covered by Identity

            base.Visit(associationType);

            #endregion

            this.AddObjectEndDumpToHashBuilder();
        }
 protected virtual void Visit(AssociationType associationType)
 {
     foreach (var endMember in associationType.AssociationEndMembers)
     {
         Visit(endMember);
     }
     Visit(associationType.BaseType);
     foreach (var keyMember in associationType.KeyMembers)
     {
         Visit(keyMember);
     }
     foreach (var member in associationType.GetDeclaredOnlyMembers<EdmMember>())
     {
         Visit(member);
     }
     foreach (var item in associationType.ReferentialConstraints)
     {
         Visit(item);
     }
     foreach (var item in associationType.RelationshipEndMembers)
     {
         Visit(item);
     }
 }
        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;
        }
        private void CreateAssociationType(LoadMethodSessionState session,
            List<RelationshipDetailsRow> columns)
        {
            Debug.Assert(columns.Count != 0, "should have at least one column");

            RelationshipDetailsRow firstRow = columns[0];

            // get the entity types for the ends
            EntityType pkEntityType;
            EntityType fkEntityType;
            if (!TryGetEndEntities(session, firstRow, out pkEntityType, out fkEntityType))
            {
                return;
            }

            if (!AreRelationshipColumnsTheTypesEntireKey(pkEntityType, columns, r => r.PKColumn))
            {
                session.AddErrorsForType(pkEntityType, new EdmSchemaError(Strings.UnsupportedDbRelationship(firstRow.RelationshipName), (int)ModelBuilderErrorCode.UnsupportedDbRelationship, EdmSchemaErrorSeverity.Warning));
                return;
                         
            }
            UniqueIdentifierService usedEndNames = new UniqueIdentifierService(false);
            // figure out the lower bound of the pk end
            bool someFkColmnsAreNullable;
            if (_targetEntityFrameworkVersion == EntityFrameworkVersions.Version1)
            {
                someFkColmnsAreNullable = AreAllFkKeyColumnsNullable(fkEntityType, columns);
            }
            else
            {
                someFkColmnsAreNullable = AreAnyFkKeyColumnsNullable(fkEntityType, columns);
            }

            RelationshipMultiplicity pkMultiplicity = someFkColmnsAreNullable ? RelationshipMultiplicity.ZeroOrOne : RelationshipMultiplicity.One;
            //Get the Delete Action for the end and set it.
            //The only DeleteAction we support is Cascade, ignor all others for now.
            OperationAction onDeleteAction = OperationAction.None;
            if (firstRow.RelationshipIsCascadeDelete)
            {
                onDeleteAction = OperationAction.Cascade;
            }
            
            AssociationEndMember pkEnd = CreateAssociationEnd( session,
                        pkEntityType,
                        pkMultiplicity,
                        usedEndNames, onDeleteAction);

            RelationshipMultiplicity fkMultiplicity = RelationshipMultiplicity.Many;

            if ( !someFkColmnsAreNullable &&
                 AreRelationshipColumnsTheTypesEntireKey(fkEntityType, columns, r => r.FKColumn))
            {
                // both the pk and fk side columns are the keys of their types
                // so this is a 1 to one relationship
                fkMultiplicity = RelationshipMultiplicity.ZeroOrOne;
            }

            AssociationEndMember fkEnd = CreateAssociationEnd(session, 
                        fkEntityType, 
                        fkMultiplicity,
                        usedEndNames, OperationAction.None);


            // create the type
            string typeName = session.UsedTypeNames.AdjustIdentifier(firstRow.RelationshipName);
            AssociationType type = new AssociationType(typeName, 
                _namespaceName, false, DataSpace.SSpace);
            type.AddMember(pkEnd);
            type.AddMember(fkEnd);

            List<EdmSchemaError> errors = new List<EdmSchemaError>();
            bool isValid = CreateReferentialConstraint(session,
                        type,
                        pkEnd,
                        fkEnd,
                        columns,
                        errors);


            string errorMessage;

            // We can skip most validation checks if the FKs are directly surfaced (since we can produce valid mappings in these cases).
            if (!this.GenerateForeignKeyProperties)
            {
                if (IsFkPartiallyContainedInPK(type, out errorMessage))
                {
                    errors.Add(new EdmSchemaError(
                        errorMessage,
                        (int)ModelBuilderErrorCode.UnsupportedForeinKeyPattern,
                        EdmSchemaErrorSeverity.Warning));
                    isValid = false;
                }

                if (isValid)
                {
                    //Now check if any FK (which could also be a PK) is shared among multiple Associations (ie shared via foreign key constraint).
                    // To do this we check if the Association Type being generated has any dependent property which is also a dependent in one of the association typed already added.
                    //If so, we keep one Association and throw the rest away.

                    foreach (var toPropertyOfAddedAssociation in session.AssociationTypes.SelectMany(t => t.ReferentialConstraints.SelectMany(refconst => refconst.ToProperties)))
                    {
                        foreach (var toProperty in type.ReferentialConstraints.SelectMany(refconst => refconst.ToProperties))
                        {
                            if (toProperty.DeclaringType.Equals(toPropertyOfAddedAssociation.DeclaringType) && toProperty.Equals(toPropertyOfAddedAssociation))
                            {
                                errors.Add(new EdmSchemaError(
                                    Strings.SharedForeignKey(type.Name, toProperty, toProperty.DeclaringType),
                                    (int)ModelBuilderErrorCode.SharedForeignKey,
                                    EdmSchemaErrorSeverity.Warning));

                                isValid = false;
                                break;
                            }
                        }

                        if (!isValid)
                        {
                            break;
                        }
                    }
                }
            }

            if (isValid)
            { 
                session.AssociationTypes.Add(type);
            }
            else
            {
                session.InvalidTypes.Add(type);
                session.RelationshipEndTypeLookup.Remove(pkEnd);
                session.RelationshipEndTypeLookup.Remove(fkEnd);
            }


            type.SetReadOnly();
            session.AddErrorsForType(type, errors);
        }
        private AssociationSet CreateAssociationSet(LoadMethodSessionState session, 
            AssociationType type)
        {
            AssociationSet set = new AssociationSet(type.Name, type);

            foreach(AssociationEndMember end in type.RelationshipEndMembers)
            {
                EntitySet entitySet = session.GetEntitySet(end);
                DbObjectKey key = session.GetKey(entitySet.ElementType);
                AssociationSetEnd setEnd = new AssociationSetEnd(entitySet, set, end);
                set.AddAssociationSetEnd(setEnd);
            }

            set.SetReadOnly();
            return set;
        }
        private void CreateModelNavigationProperties(LoadMethodSessionState session, AssociationType association)
        {
            Debug.Assert(association.Members.Count == 2, "this code assumes two ends");
            AssociationEndMember end1 = (AssociationEndMember)association.Members[0];
            AssociationEndMember end2 = (AssociationEndMember)association.Members[1];

            CreateModelNavigationProperty(session, end1, end2);
            CreateModelNavigationProperty(session, end2, end1);
        }
 /// <summary>
 /// Initializes a new instance of AssocationSet with the given name and the association type
 /// </summary>
 /// <param name="name">The name of the Assocation set</param>
 /// <param name="associationType">The association type of the entities that this associationship set type contains</param>
 internal AssociationSet(string name, AssociationType associationType)
     : base(name, null, null, null, associationType)
 {
 }
        private AssociationType CreateModelAssociationType(LoadMethodSessionState session, AssociationType storeAssociationType)
        {
            UniqueIdentifierService usedEndMemberNames = new UniqueIdentifierService(false);
            string name = CreateModelName(storeAssociationType.Name, session.UsedGlobalModelTypeNames);

            bool isFkAssociation = false;
            if (_targetEntityFrameworkVersion > EntityFrameworkVersions.Version1)
            {
                isFkAssociation = this.GenerateForeignKeyProperties || RequiresModelReferentialConstraint(storeAssociationType);
            }
            AssociationType association = new AssociationType(name,
                _namespaceName,
                isFkAssociation,
                DataSpace.CSpace);
            KeyValuePair<string, RelationshipMultiplicity> endMultiplicityOverride = CreateEndMultiplicityOverride(session, storeAssociationType, association);

            foreach (AssociationEndMember storeEndMember in storeAssociationType.RelationshipEndMembers)
            {
                AssociationEndMember end = CreateAssociationEndMember(session, storeEndMember, endMultiplicityOverride, usedEndMemberNames);
                session.MappingLookups.StoreAssociationEndMemberToModelAssociationEndMember.Add(storeEndMember, end);
                association.AddMember(end);
            }

            ReferentialConstraint constraint = CreateReferentialConstraint(session, storeAssociationType);
            if (constraint != null)
            {
                association.AddReferentialConstraint(constraint);
            }

            CreateModelNavigationProperties(session, association);

            return association;
        }
        /// <summary>
        /// This method loads all the relationship type that this entity takes part in
        /// </summary>
        /// <param name="entityType"></param>
        /// <param name="context"></param>
        private void LoadRelationshipTypes()
        {
            foreach (EdmRelationshipAttribute roleAttribute in SourceAssembly.GetCustomAttributes(typeof(EdmRelationshipAttribute), false /*inherit*/))
            {
                // Check if there is an entry already with this name
                if (TryFindNullParametersInRelationshipAttribute(roleAttribute))
                {
                    // don't give more errors for these same bad parameters
                    continue;
                }

                bool errorEncountered = false;

                // return error if the role names are the same
                if (roleAttribute.Role1Name == roleAttribute.Role2Name)
                {
                    SessionData.EdmItemErrors.Add(new EdmItemError(System.Data.Entity.Strings.SameRoleNameOnRelationshipAttribute(roleAttribute.RelationshipName, roleAttribute.Role2Name),
                               null));
                    errorEncountered = true;
                }


                if (!errorEncountered)
                {
                    AssociationType associationType = new AssociationType(roleAttribute.RelationshipName, roleAttribute.RelationshipNamespaceName, roleAttribute.IsForeignKey, DataSpace.OSpace);
                    SessionData.TypesInLoading.Add(associationType.FullName, associationType);
                    TrackClosure(roleAttribute.Role1Type);
                    TrackClosure(roleAttribute.Role2Type);

                    // prevent lifting of loop vars
                    string r1Name = roleAttribute.Role1Name;
                    Type r1Type = roleAttribute.Role1Type;
                    RelationshipMultiplicity r1Multiplicity = roleAttribute.Role1Multiplicity;
                    AddTypeResolver(() =>
                        ResolveAssociationEnd(associationType, r1Name, r1Type, r1Multiplicity));

                    // prevent lifting of loop vars
                    string r2Name = roleAttribute.Role2Name;
                    Type r2Type = roleAttribute.Role2Type;
                    RelationshipMultiplicity r2Multiplicity = roleAttribute.Role2Multiplicity;
                    AddTypeResolver(() =>
                        ResolveAssociationEnd(associationType, r2Name, r2Type, r2Multiplicity));

                    // get assembly entry and add association type to the list of types in the assembly
                    Debug.Assert(!CacheEntry.ContainsType(associationType.FullName), "Relationship type must not be present in the list of types");
                    CacheEntry.TypesInAssembly.Add(associationType);
                }
            }
        }
        private ReferentialConstraint CreateReferentialConstraint(LoadMethodSessionState session, AssociationType storeAssociation)
        {
            Debug.Assert(session != null, "session parameter is null");
            Debug.Assert(storeAssociation != null, "storeAssociation parameter is null");
            Debug.Assert(storeAssociation.ReferentialConstraints.Count <= 1, "We don't have a reason to have more than one constraint yet");

            // does the store have any constraints
            if (storeAssociation.ReferentialConstraints.Count == 0)
            {    
                return null;
            }

            ReferentialConstraint storeConstraint = storeAssociation.ReferentialConstraints[0];
            Debug.Assert(storeConstraint.FromProperties.Count == storeConstraint.ToProperties.Count, "FromProperties and ToProperties have different counts");
            Debug.Assert(storeConstraint.FromProperties.Count != 0, "No properties in the constraint, why does the constraint exist?");
            Debug.Assert(storeConstraint.ToProperties[0].DeclaringType.BuiltInTypeKind == BuiltInTypeKind.EntityType, "The property is not from an EntityType");

            EntityType toType = (EntityType)storeConstraint.ToProperties[0].DeclaringType;
            // If we are generating foreign keys, there is always a referential constraint. Otherwise, check
            // if the dependent end includes key properties. If so, this implies that there is a referential
            // constraint. Otherwise, it is assumed that the foreign key properties are not defined in the 
            // entity (verified ealier).
            if (!this.GenerateForeignKeyProperties && !RequiresModelReferentialConstraint(storeConstraint, toType)) 
            {
                return null;
            }
            // we need a constraint so lets build it
            int count = storeConstraint.FromProperties.Count;
            EdmProperty[] fromProperties = new EdmProperty[count];
            EdmProperty[] toProperties = new EdmProperty[count];
            AssociationEndMember fromRole = session.MappingLookups.StoreAssociationEndMemberToModelAssociationEndMember[(AssociationEndMember)storeConstraint.FromRole];
            AssociationEndMember toRole = session.MappingLookups.StoreAssociationEndMemberToModelAssociationEndMember[(AssociationEndMember)storeConstraint.ToRole];
            for (int index = 0; index < count; index++)
            {
                fromProperties[index] = session.MappingLookups.StoreEdmPropertyToModelEdmProperty[storeConstraint.FromProperties[index]];
                toProperties[index] = session.MappingLookups.StoreEdmPropertyToModelEdmProperty[storeConstraint.ToProperties[index]];
            }

            ReferentialConstraint newConstraint = new ReferentialConstraint(
                fromRole,
                toRole,
                fromProperties,
                toProperties);

            return newConstraint;
        }
 private void ResolveAssociationEnd(AssociationType associationType, string roleName, Type clrType, RelationshipMultiplicity multiplicity)
 {
     EntityType entityType;
     if (!TryGetRelationshipEndEntityType(clrType, out entityType))
     {
         SessionData.EdmItemErrors.Add(new EdmItemError(System.Data.Entity.Strings.RoleTypeInEdmRelationshipAttributeIsInvalidType(associationType.Name, roleName, clrType),
                    null));
         return;
     }
     associationType.AddKeyMember(new AssociationEndMember(roleName, entityType.GetReferenceType(), multiplicity));
 }
示例#26
0
        /// <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;
        }
        private void CreateRelationships()
        {
            if (SessionData.ConventionBasedRelationshipsAreLoaded)
            {
                return;                
            }
            
            
            SessionData.ConventionBasedRelationshipsAreLoaded = true;

            // find all the relationships
            foreach (AssociationType cspaceAssociation in SessionData.EdmItemCollection.GetItems<AssociationType>())
            {
                Debug.Assert(cspaceAssociation.RelationshipEndMembers.Count == 2, "Relationships are assumed to have exactly two ends");

                if (SessionData.CspaceToOspace.ContainsKey(cspaceAssociation))
                {
                    // don't try to load relationships that we already know about
                    continue;
                }

                EdmType[] ospaceEndTypes = new EdmType[2];
                if (SessionData.CspaceToOspace.TryGetValue(GetRelationshipEndType(cspaceAssociation.RelationshipEndMembers[0]), out ospaceEndTypes[0]) &&
                    SessionData.CspaceToOspace.TryGetValue(GetRelationshipEndType(cspaceAssociation.RelationshipEndMembers[1]), out ospaceEndTypes[1]))
                {
                    Debug.Assert(ospaceEndTypes[0] is StructuralType);
                    Debug.Assert(ospaceEndTypes[1] is StructuralType);

                    // if we can find both ends of the relationship, then create it

                    AssociationType ospaceAssociation = new AssociationType(cspaceAssociation.Name, cspaceAssociation.NamespaceName, cspaceAssociation.IsForeignKey, DataSpace.OSpace);
                    for (int i = 0; i < cspaceAssociation.RelationshipEndMembers.Count; i++)
                    {
                        EntityType ospaceEndType = (EntityType)ospaceEndTypes[i];
                        RelationshipEndMember cspaceEnd = cspaceAssociation.RelationshipEndMembers[i];

                        ospaceAssociation.AddKeyMember(new AssociationEndMember(cspaceEnd.Name, ospaceEndType.GetReferenceType(), cspaceEnd.RelationshipMultiplicity));
                    }
                    CacheEntry.TypesInAssembly.Add(ospaceAssociation);
                    SessionData.TypesInLoading.Add(ospaceAssociation.FullName, ospaceAssociation);
                    SessionData.CspaceToOspace.Add(cspaceAssociation, ospaceAssociation); 

                }
            }
        }
        /// <summary>
        /// True if the specified association type is 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 IsIdentifyingRelationship(AssociationType association)
        {
            if (association == null)
            {
                throw new ArgumentNullException("association");
            }

            return IsPrincipalEndOfIdentifyingRelationship(association.AssociationEndMembers[0]) || IsPrincipalEndOfIdentifyingRelationship(association.AssociationEndMembers[1]);
        }
示例#29
0
        /// <summary>
        /// Converts an association type from SOM to metadata
        /// </summary>
        /// <param name="element">The SOM element to process</param>
        /// <param name="providerManifest">The provider manifest to be used for conversion</param>
        /// <param name="convertedItemCache">The item collection for currently existing metadata objects</param>
        /// <param name="newGlobalItems">The new GlobalItem objects that are created as a result of this conversion</param>
        /// <returns>The association type object resulting from the convert</returns>
        private static AssociationType ConvertToAssociationType(Som.Relationship element,
                                                                DbProviderManifest providerManifest,
                                                                ConversionCache convertedItemCache,
                                                                Dictionary<Som.SchemaElement, GlobalItem> newGlobalItems)
        {
            Debug.Assert(element.RelationshipKind == RelationshipKind.Association);

            AssociationType associationType = new AssociationType(element.Name,
                                                                  element.Namespace,
                                                                  element.IsForeignKey,
                                                                  GetDataSpace(providerManifest));
            newGlobalItems.Add(element, associationType);

            foreach (Som.RelationshipEnd end in element.Ends)
            {
                Som.SchemaType entityTypeElement = end.Type;
                EntityType endEntityType = (EntityType)LoadSchemaElement(entityTypeElement,
                                                                providerManifest,
                                                                convertedItemCache,
                                                                newGlobalItems);

                AssociationEndMember endMember = InitializeAssociationEndMember(associationType, end, endEntityType);
                AddOtherContent(end, endMember);
                // Loop through and convert the operations
                foreach (Som.OnOperation operation in end.Operations)
                {
                    // Process only the ones that we recognize
                    if (operation.Operation != Som.Operation.Delete)
                    {
                        continue;
                    }

                    // Determine the action for this operation
                    OperationAction action = OperationAction.None;
                    switch (operation.Action)
                    {
                        case Som.Action.Cascade:
                            action = OperationAction.Cascade;
                            break;
                        case Som.Action.None:
                            action = OperationAction.None;
                            break;
                        default:
                            Debug.Fail("Operation action not supported.");
                            break;
                    }
                    endMember.DeleteBehavior = action;
                }

                // Extract optional Documentation from the end element
                if (end.Documentation != null)
                {
                    endMember.Documentation = ConvertToDocumentation(end.Documentation);
                }
            }

            Debug.Assert(associationType.ReferentialConstraints.Count == 0, "This must never have been initialized");

            for (int i = 0; i < element.Constraints.Count; i++)
            {
                Som.ReferentialConstraint constraint = element.Constraints[i];
                AssociationEndMember fromMember = (AssociationEndMember)associationType.Members[constraint.PrincipalRole.Name];
                AssociationEndMember toMember = (AssociationEndMember)associationType.Members[constraint.DependentRole.Name];
                EntityTypeBase fromEntityType = ((RefType)fromMember.TypeUsage.EdmType).ElementType;
                EntityTypeBase toEntityType = ((RefType)toMember.TypeUsage.EdmType).ElementType;

                ReferentialConstraint referentialConstraint = new ReferentialConstraint(fromMember, toMember,
                                                                                        GetProperties(fromEntityType, constraint.PrincipalRole.RoleProperties),
                                                                                        GetProperties(toEntityType, constraint.DependentRole.RoleProperties));

                // Attach the optional Documentation
                if (constraint.Documentation != null)
                    referentialConstraint.Documentation = ConvertToDocumentation(constraint.Documentation);
                if (constraint.PrincipalRole.Documentation != null)
                    referentialConstraint.FromRole.Documentation = ConvertToDocumentation(constraint.PrincipalRole.Documentation);
                if (constraint.DependentRole.Documentation != null)
                    referentialConstraint.ToRole.Documentation = ConvertToDocumentation(constraint.DependentRole.Documentation);


                associationType.AddReferentialConstraint(referentialConstraint);
                AddOtherContent(element.Constraints[i], referentialConstraint);

            }

            // Extract the optional Documentation
            if (element.Documentation != null)
            {
                associationType.Documentation = ConvertToDocumentation(element.Documentation);
            }
            AddOtherContent(element, associationType);

            return associationType;
        }
 public bool TryGetNavigationPropertyAssociationType(string relationshipName, string targetRoleName, out AssociationType associationType)
 {
     return _navigationPropertyAssociationTypes.TryGetValue(new Tuple<string, string>(relationshipName, targetRoleName), out associationType);
 }
示例#31
0
        /// <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;
        }
 /// <summary>
 /// Construct the new AssociationTypeMapping object.
 /// </summary>
 /// <param name="relation">Represents the Association Type metadata object</param>
 /// <param name="setMapping">Set Mapping that contains this Type mapping </param>
 internal StorageAssociationTypeMapping(AssociationType relation, StorageSetMapping setMapping)
     : base(setMapping) {
     this.m_relation = relation;
 }
 /// <summary>
 /// A mechanism to lookup AssociationType metadata for proxies for a given entity and association information
 /// </summary>
 /// <param name="wrappedEntity">The entity instance used to lookup the proxy type</param>
 /// <param name="relationshipName">The name of the relationship (FullName or Name)</param>
 /// <param name="targetRoleName">Target role of the relationship</param>
 /// <param name="associationType">The AssociationType for that property</param>
 /// <returns>True if an AssociationType is found in proxy metadata, false otherwise</returns>
 internal static bool TryGetAssociationTypeFromProxyInfo(IEntityWrapper wrappedEntity, string relationshipName, string targetRoleName, out AssociationType associationType)
 {
     EntityProxyTypeInfo proxyInfo = null;
     associationType = null;
     return (EntityProxyFactory.TryGetProxyType(wrappedEntity.Entity.GetType(), out proxyInfo) && proxyInfo != null &&
             proxyInfo.TryGetNavigationPropertyAssociationType(relationshipName, targetRoleName, out associationType));
 }