/// <summary>
        /// Returns the association information for the specified navigation property.
        /// </summary>
        /// <param name="navigationProperty">The navigation property to return association information for</param>
        /// <returns>The association info</returns>
        internal AssociationInfo GetAssociationInfo(NavigationProperty navigationProperty)
        {
            return _associationMap.GetOrAdd(navigationProperty.RelationshipType.FullName, associationName =>
            {
                AssociationType associationType = (AssociationType)navigationProperty.RelationshipType;

                if (!associationType.ReferentialConstraints.Any())
                {
                    // We only support EF models where FK info is part of the model.
                    throw Error.NotSupported(Resource.LinqToEntitiesProvider_UnableToRetrieveAssociationInfo, associationName);
                }

                string toRoleName = associationType.ReferentialConstraints[0].ToRole.Name;
                AssociationInfo associationInfo = new AssociationInfo()
                {
                    FKRole = toRoleName,
                    Name = GetAssociationName(navigationProperty, toRoleName),
                    ThisKey = associationType.ReferentialConstraints[0].ToProperties.Select(p => p.Name).ToArray(),
                    OtherKey = associationType.ReferentialConstraints[0].FromProperties.Select(p => p.Name).ToArray(),
                    IsRequired = associationType.RelationshipEndMembers[0].RelationshipMultiplicity == RelationshipMultiplicity.One
                };

                return associationInfo;
            });
        }
Exemple #2
0
        private void CreateAndAddNavigationProperty(StructuralType cspaceType, StructuralType ospaceType, NavigationProperty cspaceProperty, PropertyInfo clrProperty)
        {
            EdmType ospaceRelationship;

            if (SessionData.CspaceToOspace.TryGetValue(cspaceProperty.RelationshipType, out ospaceRelationship))
            {
                Debug.Assert(ospaceRelationship is StructuralType, "Structural type expected.");

                bool    foundTarget = false;
                EdmType targetType  = null;
                if (Helper.IsCollectionType(cspaceProperty.TypeUsage.EdmType))
                {
                    EdmType findType;
                    foundTarget = SessionData.CspaceToOspace.TryGetValue((StructuralType)((CollectionType)cspaceProperty.TypeUsage.EdmType).TypeUsage.EdmType, out findType);
                    if (foundTarget)
                    {
                        Debug.Assert(findType is StructuralType, "Structural type expected.");

                        targetType = findType.GetCollectionType();
                    }
                }
                else
                {
                    EdmType findType;
                    foundTarget = SessionData.CspaceToOspace.TryGetValue((StructuralType)cspaceProperty.TypeUsage.EdmType, out findType);
                    if (foundTarget)
                    {
                        Debug.Assert(findType is StructuralType, "Structural type expected.");

                        targetType = findType;
                    }
                }


                Debug.Assert(foundTarget, "Since the relationship will only be created if it can find the types for both ends, we will never fail to find one of the ends");

                NavigationProperty navigationProperty = new NavigationProperty(cspaceProperty.Name, TypeUsage.Create(targetType), clrProperty);
                navigationProperty.RelationshipType = (RelationshipType)ospaceRelationship;

                // we can use First because o-space relationships are created directly from
                // c-space relationship
                navigationProperty.ToEndMember   = (RelationshipEndMember)((RelationshipType)ospaceRelationship).Members.First(e => e.Name == cspaceProperty.ToEndMember.Name);
                navigationProperty.FromEndMember = (RelationshipEndMember)((RelationshipType)ospaceRelationship).Members.First(e => e.Name == cspaceProperty.FromEndMember.Name);
                ospaceType.AddMember(navigationProperty);
            }
            else
            {
                EntityTypeBase missingType = cspaceProperty.RelationshipType.RelationshipEndMembers.Select(e => ((RefType)e.TypeUsage.EdmType).ElementType).First(e => e != cspaceType);
                string         message     =
                    SessionData.LoadMessageLogger.CreateErrorMessageWithTypeSpecificLoadLogs(
                        Strings.Validator_OSpace_Convention_RelationshipNotLoaded(cspaceProperty.RelationshipType.FullName, missingType.FullName),
                        missingType);
                SessionData.EdmItemErrors.Add(new EdmItemError(message, ospaceType));
            }
        }
        /// <summary>
        /// Given a property on the principal end of a referential constraint, returns the corresponding property on the dependent end.
        /// Requires: The association has a referential constraint, and the specified principalProperty is one of the properties on the principal end.
        /// </summary>
        public EdmProperty GetCorrespondingDependentProperty(NavigationProperty navProperty, EdmProperty principalProperty)
        {
            if (navProperty == null)
            {
                throw new ArgumentNullException("navProperty");
            }

            if (principalProperty == null)
            {
                throw new ArgumentNullException("principalProperty");
            }

            ReadOnlyMetadataCollection<EdmProperty> fromProperties = GetPrincipalProperties(navProperty);
            ReadOnlyMetadataCollection<EdmProperty> toProperties = GetDependentProperties(navProperty);
            return toProperties[fromProperties.IndexOf(principalProperty)];
        }
        public EFAssociationProvider(EFColumnProvider column, NavigationProperty navigationProperty) {
            FromColumn = column;

            var entityMemberParentEntity = (EFTableProvider)column.Table;
            var parentEntityModel = (EFDataModelProvider)entityMemberParentEntity.DataModel;

            EFColumnProvider columnProvider;
            EntityType otherEntityType = navigationProperty.ToEndMember.GetEntityType();

            // If we can get to the entityType of the ToMember side of the relaionship then build a relationship key and try to lookup the column provider.
            if (otherEntityType != null) {
                long key = BuildRelationshipKey(otherEntityType, navigationProperty.ToEndMember);
                if (parentEntityModel.RelationshipEndLookup.TryGetValue(key, out columnProvider)) {
                    ToColumn = columnProvider;
                }
                else {
                    // Otherwise just lookup the entityType in the table lookup
                    ToTable = parentEntityModel.TableEndLookup[otherEntityType];
                }
            }
            else {
                EntityType value = (EntityType)navigationProperty.ToEndMember.TypeUsage.EdmType.MetadataProperties.Single(prop => prop.Name == "ElementType").Value;
                ToTable = parentEntityModel.TableEndLookup[value];
            }

            if (navigationProperty.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many) {
                if (navigationProperty.FromEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many) {
                    Direction = AssociationDirection.ManyToMany;
                }
                else {
                    Direction = AssociationDirection.OneToMany;
                }
            }
            else {
                if (navigationProperty.FromEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many) {
                    Direction = AssociationDirection.ManyToOne;
                }
                else {
                    Direction = AssociationDirection.OneToOne;
                }
            }

            // If it's a foreign key reference (as opposed to a entity set), figure out the foreign keys
            if (IsForeignKeyReference) {
                var foreignKeyNames = new List<string>();
                var primaryKeyNames = FromColumn.Table.Columns.Where(c => c.IsPrimaryKey).Select(c => c.Name);

                // Add the foreign keys for this association.
                foreignKeyNames.AddRange(GetDependentPropertyNames(navigationProperty));

                if (IsZeroOrOne(navigationProperty)) {
                    // Assume this is true for 1 to 0..1 relationships on both sides
                    IsPrimaryKeyInThisTable = true;
                }
                else {
                    // If any of the foreign keys are also PKs, set the flag                    
                    IsPrimaryKeyInThisTable = foreignKeyNames.Any(fkName => primaryKeyNames.Contains(fkName, StringComparer.OrdinalIgnoreCase));
                }

                if (!foreignKeyNames.Any()) {
                    // If we couldn't find any dependent properties, we're dealing with a model that doesn't
                    // have FKs, and requires the use of flattened FK names (e.g. Category.CategoryId)
                    foreach (ColumnProvider toEntityColumn in ToTable.Columns.Where(c => c.IsPrimaryKey)) {
                        foreignKeyNames.Add(FromColumn.Name + "." + toEntityColumn.Name);
                    }
                }

                ForeignKeyNames = foreignKeyNames.AsReadOnly();
            }
        }
 /// <summary>
 /// Validate an NavigationProperty object
 /// </summary>
 /// <param name="item">The NavigationProperty object to validate</param>
 /// <param name="errors">An error collection for adding validation errors</param>
 /// <param name="validatedItems">A dictionary keeping track of items that have been validated</param>
 private void ValidateNavigationProperty(NavigationProperty item, List <EdmItemError> errors, HashSet <MetadataItem> validatedItems)
 {
     // Continue to process the property to see if there are other errors. This allows the user to fix as much as possible at the same time.
     ValidateEdmMember(item, errors, validatedItems);
 }
        /// <summary>
        /// True if the source end of the specified navigation property is the principal in an identifying relationship.
        /// or if the source end has cascade delete defined.
        /// </summary>
        public bool IsCascadeDeletePrincipal(NavigationProperty navProperty)
        {
            if (navProperty == null)
            {
                throw new ArgumentNullException("navProperty");
            }

            return IsCascadeDeletePrincipal((AssociationEndMember)navProperty.FromEndMember);
        }
 protected virtual void Visit(NavigationProperty navigationProperty)
 {
     Visit(navigationProperty.FromEndMember);
     Visit(navigationProperty.RelationshipType);
     Visit(navigationProperty.ToEndMember);
     Visit(navigationProperty.TypeUsage);
 }
        private Node RewriteNavigationProperty(
            NavigationProperty navProperty,
            Node sourceEntityNode, TypeUsage resultType)
        {
            var relProperty = new RelProperty(navProperty.RelationshipType, navProperty.FromEndMember, navProperty.ToEndMember);
            PlanCompiler.Assert(
                m_command.IsRelPropertyReferenced(relProperty)
                || (relProperty.ToEnd.RelationshipMultiplicity == RelationshipMultiplicity.Many),
                "Unreferenced rel property? " + relProperty);

            // Handle N:1
            if ((relProperty.FromEnd.RelationshipMultiplicity == RelationshipMultiplicity.Many)
                &&
                (relProperty.ToEnd.RelationshipMultiplicity != RelationshipMultiplicity.Many))
            {
                return RewriteManyToOneNavigationProperty(relProperty, sourceEntityNode, resultType);
            }

            //
            // Find the list of all relationships that could satisfy this relationship
            // If we find no matching relationship set, simply return a null node / empty collection
            //
            var relationshipSets = GetRelationshipSets(relProperty.Relationship);
            if (relationshipSets.Count == 0)
            {
                // return an empty set / null node
                if (relProperty.ToEnd.RelationshipMultiplicity
                    == RelationshipMultiplicity.Many)
                {
                    return m_command.CreateNode(m_command.CreateNewMultisetOp(resultType));
                }
                return m_command.CreateNode(m_command.CreateNullOp(resultType));
            }

            // Build out a ref over the source entity 
            var sourceRefNode = m_command.CreateNode(
                m_command.CreateGetEntityRefOp(relProperty.FromEnd.TypeUsage),
                sourceEntityNode);

            // Hanlde the 1:M and N:M cases
            if (relProperty.ToEnd.RelationshipMultiplicity
                == RelationshipMultiplicity.Many)
            {
                // Handle N:M
                if (relProperty.FromEnd.RelationshipMultiplicity
                    == RelationshipMultiplicity.Many)
                {
                    return RewriteManyToManyNavigationProperty(relProperty, relationshipSets, sourceRefNode);
                }
                // Handle 1:M
                return RewriteOneToManyNavigationProperty(relProperty, relationshipSets, sourceRefNode);
            }

            // Handle 1:1
            return RewriteOneToOneNavigationProperty(relProperty, relationshipSets, sourceRefNode);
        }
        /// <summary>
        /// Gets the collection of properties that are on the principal end of a referential constraint for the specified navigation property.
        /// Requires: The association has a referential constraint.
        /// </summary>
        public ReadOnlyMetadataCollection<EdmProperty> GetPrincipalProperties(NavigationProperty navProperty)
        {
            if (navProperty == null)
            {
                throw new ArgumentNullException("navProperty");
            }

            return ((AssociationType)navProperty.RelationshipType).ReferentialConstraints[0].FromProperties;
        }
        private static bool IsModifed(NavigationProperty navigationProperty, IEnumerable<string> modifiedMembers)
        {
            var association = navigationProperty.RelationshipType as AssociationType;
            if (association == null)
                return false;

            var referentialConstraint = association.ReferentialConstraints.FirstOrDefault();
            if (referentialConstraint == null)
                return false;

            var toProperties = referentialConstraint
                .ToProperties
                .Select(p => p.Name)
                .ToList();

            return modifiedMembers.Intersect(toProperties).Any();
        }
 /// <summary>
 /// Constrcut a new member mapping metadata object
 /// </summary>
 /// <param name="edmNavigationProperty"></param>
 /// <param name="clrNavigationProperty"></param>
 internal ObjectNavigationPropertyMapping(NavigationProperty edmNavigationProperty, NavigationProperty clrNavigationProperty)
     :
         base(edmNavigationProperty, clrNavigationProperty)
 {
 }
        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);
            }
        }
        /// <summary>
        /// Returns a unique association name for the specified navigation property.
        /// </summary>
        /// <param name="navigationProperty">The navigation property</param>
        /// <param name="foreignKeyRoleName">The foreign key role name for the property's association</param>
        /// <returns>A unique association name for the specified navigation property.</returns>
        private string GetAssociationName(NavigationProperty navigationProperty, string foreignKeyRoleName)
        {
            RelationshipEndMember fromMember = navigationProperty.FromEndMember;
            RelationshipEndMember toMember = navigationProperty.ToEndMember;

            RefType toRefType = toMember.TypeUsage.EdmType as RefType;
            EntityType toEntityType = toRefType.ElementType as EntityType;

            RefType fromRefType = fromMember.TypeUsage.EdmType as RefType;
            EntityType fromEntityType = fromRefType.ElementType as EntityType;

            bool isForeignKey = navigationProperty.FromEndMember.Name == foreignKeyRoleName;
            string fromTypeName = isForeignKey ? fromEntityType.Name : toEntityType.Name;
            string toTypeName = isForeignKey ? toEntityType.Name : fromEntityType.Name;

            // names are always formatted non-FK side type name followed by FK side type name
            string associationName = String.Format(CultureInfo.InvariantCulture, "{0}_{1}", toTypeName, fromTypeName);
            associationName = MakeUniqueName(associationName, _associationMap.Values.Select(p => p.Name));

            return associationName;
        }
 /// <summary>
 /// Attempts to get the property name for the assoication between the two given end
 /// names.  Note that this property may not exist if a navigation property is defined
 /// in one direction but not in the other.
 /// </summary>
 /// <param name="relationshipType">the relationship for which a nav property is required</param>
 /// <param name="fromName">the 'from' end of the association</param>
 /// <param name="toName">the 'to' end of the association</param>
 /// <param name="navigationProperty">the property name, or null if none was found</param>
 /// <returns>true if a property was found, false otherwise</returns>
 internal bool TryGetNavigationProperty(
     string relationshipType, string fromName, string toName, out NavigationProperty navigationProperty)
 {
     // This is a linear search but it's probably okay because the number of entries
     // is generally small and this method is only called to generate code during lighweight
     // code gen.
     foreach (var navProperty in NavigationProperties)
     {
         if (navProperty.RelationshipType.FullName == relationshipType &&
             navProperty.FromEndMember.Name == fromName
             &&
             navProperty.ToEndMember.Name == toName)
         {
             navigationProperty = navProperty;
             return true;
         }
     }
     navigationProperty = null;
     return false;
 }
 /// <summary>
 /// Attempts to get the property name for the ----oication between the two given end
 /// names.  Note that this property may not exist if a navigation property is defined
 /// in one direction but not in the other.
 /// </summary>
 /// <param name="relationshipType">the relationship for which a nav property is required</param>
 /// <param name="fromName">the 'from' end of the association</param>
 /// <param name="toName">the 'to' end of the association</param>
 /// <param name="navigationProperty">the property name, or null if none was found</param>
 /// <returns>true if a property was found, false otherwise</returns>
 internal bool TryGetNavigationProperty(string relationshipType, string fromName, string toName, out NavigationProperty navigationProperty)
 {
     // This is a linear search but it's probably okay because the number of entries
     // is generally small and this method is only called to generate code during lighweight
     // code gen.
     foreach (NavigationProperty navProperty in NavigationProperties)
     {
         if (navProperty.RelationshipType.FullName == relationshipType &&
             navProperty.FromEndMember.Name == fromName &&
             navProperty.ToEndMember.Name == toName)
         {
             navigationProperty = navProperty;
             return(true);
         }
     }
     navigationProperty = null;
     return(false);
 }
 protected override void Visit(NavigationProperty navigationProperty)
 {
     // navigation properties are not considered in view generation
     return;
 }
        /// <summary>
        ///     Gets the type of entity or entities at the target end of the given navigation property.
        /// </summary>
        /// <param name = "navigationProperty">The navigation property.</param>
        /// <returns>The CLR type of the entity or entities at the other end.</returns>
        private Type GetNavigationTargetType(NavigationProperty navigationProperty)
        {
            var metadataWorkspace = _internalContext.ObjectContext.MetadataWorkspace;

            var cSpaceType =
                navigationProperty.RelationshipType.RelationshipEndMembers.Single(
                    e => navigationProperty.ToEndMember.Name == e.Name).
                    GetEntityType();
            var oSpaceType = metadataWorkspace.GetObjectSpaceType(cSpaceType);

            var objectItemCollection = (ObjectItemCollection)metadataWorkspace.GetItemCollection(DataSpace.OSpace);
            return objectItemCollection.GetClrType(oSpaceType);
        }
        /// <summary>
        /// Creates an AssociationAttribute for the specified navigation property
        /// </summary>
        /// <param name="navigationProperty">The navigation property that corresponds to the association (it identifies the end points)</param>
        /// <returns>A new AssociationAttribute that describes the given navigation property association</returns>
        internal AssociationAttribute CreateAssociationAttribute(NavigationProperty navigationProperty)
        {
            AssociationInfo assocInfo = GetAssociationInfo(navigationProperty);
            bool isForeignKey = navigationProperty.FromEndMember.Name == assocInfo.FKRole;
            string thisKey;
            string otherKey;
            if (isForeignKey)
            {
                thisKey = String.Join(",", assocInfo.ThisKey);
                otherKey = String.Join(",", assocInfo.OtherKey);
            }
            else
            {
                otherKey = String.Join(",", assocInfo.ThisKey);
                thisKey = String.Join(",", assocInfo.OtherKey);
            }

            AssociationAttribute assocAttrib = new AssociationAttribute(assocInfo.Name, thisKey, otherKey);
            assocAttrib.IsForeignKey = isForeignKey;
            return assocAttrib;
        }
 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 void CreateAndAddNavigationProperty(StructuralType cspaceType, StructuralType ospaceType, NavigationProperty cspaceProperty, PropertyInfo clrProperty)
        {
            EdmType ospaceRelationship;
            if (SessionData.CspaceToOspace.TryGetValue(cspaceProperty.RelationshipType, out ospaceRelationship))
            {
                Debug.Assert(ospaceRelationship is StructuralType, "Structural type expected.");

                bool foundTarget = false;
                EdmType targetType = null;
                if (Helper.IsCollectionType(cspaceProperty.TypeUsage.EdmType))
                {
                    EdmType findType;
                    foundTarget = SessionData.CspaceToOspace.TryGetValue((StructuralType)((CollectionType)cspaceProperty.TypeUsage.EdmType).TypeUsage.EdmType, out findType);
                    if (foundTarget)
                    {
                        Debug.Assert(findType is StructuralType, "Structural type expected.");

                        targetType = findType.GetCollectionType();
                    }
                }
                else
                {
                    EdmType findType;
                    foundTarget = SessionData.CspaceToOspace.TryGetValue((StructuralType)cspaceProperty.TypeUsage.EdmType, out findType);
                    if (foundTarget)
                    {
                        Debug.Assert(findType is StructuralType, "Structural type expected.");

                        targetType = findType;
                    }
                }


                Debug.Assert(foundTarget, "Since the relationship will only be created if it can find the types for both ends, we will never fail to find one of the ends");

                NavigationProperty navigationProperty = new NavigationProperty(cspaceProperty.Name, TypeUsage.Create(targetType), clrProperty);
                navigationProperty.RelationshipType = (RelationshipType)ospaceRelationship;

                // we can use First because o-space relationships are created directly from 
                // c-space relationship
                navigationProperty.ToEndMember = (RelationshipEndMember)((RelationshipType)ospaceRelationship).Members.First(e => e.Name == cspaceProperty.ToEndMember.Name);
                navigationProperty.FromEndMember = (RelationshipEndMember)((RelationshipType)ospaceRelationship).Members.First(e => e.Name == cspaceProperty.FromEndMember.Name);
                ospaceType.AddMember(navigationProperty);
            }
            else
            {
                EntityTypeBase missingType = cspaceProperty.RelationshipType.RelationshipEndMembers.Select(e => ((RefType)e.TypeUsage.EdmType).ElementType).First(e => e != cspaceType);
                string message =
                    SessionData.LoadMessageLogger.CreateErrorMessageWithTypeSpecificLoadLogs(
                        Strings.Validator_OSpace_Convention_RelationshipNotLoaded(cspaceProperty.RelationshipType.FullName, missingType.FullName),
                        missingType);
                SessionData.EdmItemErrors.Add(new EdmItemError(message, ospaceType));
            }
        }
 /// <summary>
 /// 
 /// </summary>
 /// <param name="generator"></param>
 /// <param name="navigationProperty"></param>
 public NavigationPropertyEmitter(ClientApiGenerator generator, NavigationProperty navigationProperty, bool declaringTypeUsesStandardBaseType)
     : base(generator, navigationProperty, declaringTypeUsesStandardBaseType)
 {
 }
 /// <summary>
 /// Dumps the specified Navigation Property EdmMember metadata instance with the specified decoration
 /// </summary>
 /// <param name="navProp">The Navigation Property metadata to dump</param>
 /// <param name="name">The decorating block name</param>
 internal void Dump(NavigationProperty navProp, string name)
 {
     Begin(name);
     Begin(
         "NavigationProperty",
         "Name", navProp.Name,
         //"IsParent", end.IsParent,
         "RelationshipTypeName", navProp.RelationshipType.FullName,
         "ToEndMemberName", navProp.ToEndMember.Name
     );
     Dump(navProp.DeclaringType, "DeclaringType");
     Dump(navProp.TypeUsage, "PropertyType");
     End("NavigationProperty");
     End(name);
 }
        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);
            }
        }
        protected EntityDataSourceReferenceValueColumn(MetadataWorkspace ocWorkspace, NavigationProperty navigationProperty)
            : base(EntityDataSourceUtil.CheckArgumentNull(navigationProperty, "navigationProperty").Name)
        {
            EntityDataSourceUtil.CheckArgumentNull(ocWorkspace, "ocWorkspace");

            this.navigationProperty = navigationProperty;
        }
        /// <summary>
        /// Returns the NavigationProperty that is the other end of the same association set if it is
        /// available, otherwise it returns null.
        /// </summary>
        public NavigationProperty Inverse(NavigationProperty navProperty)
        {
            if (navProperty == null)
            {
                return null;
            }

            EntityType toEntity = navProperty.ToEndMember.GetEntityType();
            return toEntity.NavigationProperties
                .SingleOrDefault(n => Object.ReferenceEquals(n.RelationshipType, navProperty.RelationshipType) && !Object.ReferenceEquals(n, navProperty));
        }
        internal static IEnumerable<string> GetDependentPropertyNames(NavigationProperty navigationProperty, bool checkRelationshipType) {
            if (checkRelationshipType) {
                if (navigationProperty.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.ZeroOrOne &&
                    navigationProperty.FromEndMember.RelationshipMultiplicity == RelationshipMultiplicity.One) {
                    // Get constraint when this association is on the "parent" (aka "from") side. This means
                    // that the navProperty represents a Children association in a 1-1 relationship. For example,
                    // this could be a Item-ItemDetail scenario where the ItemDetail table has a PK that is also an FK
                    // into the Item table (thus ensuring the 1-1 cardinality). We need to special case this situation because normally we would try
                    // to build a foreign key name of the form "Item.ItemID", but we want just "ItemID".
                    AssociationType relationshipType = (AssociationType)navigationProperty.RelationshipType;
                    ReferentialConstraint constraint = relationshipType.ReferentialConstraints.FirstOrDefault(c => c.ToRole == navigationProperty.ToEndMember);
                    if (constraint != null) {
                        return constraint.FromProperties.Select(p => p.Name);
                    }

                    // Fall back on the primary keys if no constraints were found but only if we are on the parent side. i.e the 1 side Item side in an Item-ItemDetail
                    // Get the primary keys on the "from" side of the relationship. i.e Product.Category -> ProductID
                    return navigationProperty.FromEndMember.GetEntityType().KeyMembers.Select(m => m.Name);
                }
            }
            return navigationProperty.GetDependentProperties().Select(m => m.Name);
        }
 /// <summary>
 /// Retrieves the Entity (result or element) type produced by a Navigation Property.
 /// </summary>
 /// <param name="navProp">The navigation property</param>
 /// <returns>
 ///     The Entity type produced by the navigation property. 
 ///     This may be the immediate result type (if the result is at most one)
 ///     or the element type of the result type, otherwise.
 /// </returns>
 private static EntityType EntityTypeFromResultType(NavigationProperty navProp)
 {
     EntityType retType = null;
     TryGetEntityType(navProp.TypeUsage, out retType);
     // Currently, navigation properties may only return an Entity or Collection<Entity> result
     Debug.Assert(retType != null, "Navigation property has non-Entity and non-Entity collection result type?");
     return retType;
 }
        private static bool IsLoaded(AuditEntryState state, NavigationProperty navigationProperty, IMemberAccessor accessor)
        {
            var relationshipManager = state.ObjectStateEntry.RelationshipManager;
            var getEntityReference = _relatedAccessor.Value.MakeGenericMethod(accessor.MemberType);
            var parameters = new[]
            {
                navigationProperty.RelationshipType.FullName,
                navigationProperty.ToEndMember.Name
            };

            var entityReference = getEntityReference.Invoke(relationshipManager, parameters) as EntityReference;
            return (entityReference != null && entityReference.IsLoaded);
        }
        internal static EntityDataSourceReferenceValueColumn Create(Type clrToType, MetadataWorkspace ocWorkspace, NavigationProperty navigationProperty)
        {
            EntityDataSourceUtil.CheckArgumentNull(clrToType, "clrToType");

            Type columnType = typeof(EntityDataSourceReferenceValueColumn<>).MakeGenericType(clrToType);
            EntityDataSourceReferenceValueColumn result = (EntityDataSourceReferenceValueColumn)Activator.CreateInstance(columnType, ocWorkspace, navigationProperty);
            return result;
        }
 /// <summary>
 /// Utility method to retrieve the 'To' AssociationEndMember of a NavigationProperty
 /// </summary>
 /// <param name="property">The navigation property</param>
 /// <returns>The AssociationEndMember that is the target of the navigation operation represented by the NavigationProperty</returns>
 private AssociationEndMember GetNavigationPropertyTargetEnd(NavigationProperty property)
 {
     AssociationType relationship = this.Metadata.GetItem<AssociationType>(property.RelationshipType.FullName, DataSpace.CSpace);
     Debug.Assert(relationship.AssociationEndMembers.Contains(property.ToEndMember.Name), "Association does not declare member referenced by Navigation property?");
     return relationship.AssociationEndMembers[property.ToEndMember.Name];
 }
 private static bool IsZeroOrOne(NavigationProperty navigationProperty) {
     return (navigationProperty.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.ZeroOrOne &&
                         navigationProperty.FromEndMember.RelationshipMultiplicity == RelationshipMultiplicity.One) ||
                         (navigationProperty.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.One &&
                         navigationProperty.FromEndMember.RelationshipMultiplicity == RelationshipMultiplicity.ZeroOrOne);
 }
        private void EmitReferenceProperty(TypeBuilder typeBuilder, PropertyBuilder propertyBuilder, PropertyInfo baseProperty, NavigationProperty navProperty)
        {
            const MethodAttributes methodAttributes = MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Virtual;
            MethodInfo baseSetter = baseProperty.GetSetMethod(true); ;
            MethodAttributes methodAccess = baseSetter.Attributes & MethodAttributes.MemberAccessMask;

            MethodInfo specificGetRelatedReference = s_GetRelatedReference.MakeGenericMethod(baseProperty.PropertyType);
            MethodInfo specificEntityReferenceSetValue = typeof(EntityReference<>).MakeGenericType(baseProperty.PropertyType).GetMethod("set_Value"); ;

            MethodBuilder setterBuilder = typeBuilder.DefineMethod("set_" + baseProperty.Name, methodAccess | methodAttributes, null, new Type[] { baseProperty.PropertyType });
            ILGenerator generator = setterBuilder.GetILGenerator();
            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Callvirt, _getRelationshipManager);
            generator.Emit(OpCodes.Ldstr, navProperty.RelationshipType.FullName);
            generator.Emit(OpCodes.Ldstr, navProperty.ToEndMember.Name);
            generator.Emit(OpCodes.Callvirt, specificGetRelatedReference);
            generator.Emit(OpCodes.Ldarg_1);
            generator.Emit(OpCodes.Callvirt, specificEntityReferenceSetValue);
            generator.Emit(OpCodes.Ret);
            propertyBuilder.SetSetMethod(setterBuilder);

            _referenceProperties.Add(new KeyValuePair<NavigationProperty,PropertyInfo>(navProperty, baseProperty));
        }
 internal static IEnumerable<string> GetDependentPropertyNames(NavigationProperty navigationProperty) {
     return GetDependentPropertyNames(navigationProperty, true /*checkRelationshipType*/);
 }
        private void EmitCollectionProperty(TypeBuilder typeBuilder, PropertyBuilder propertyBuilder, PropertyInfo baseProperty, NavigationProperty navProperty)
        {
            const MethodAttributes methodAttributes = MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Virtual;
            MethodInfo baseSetter = baseProperty.GetSetMethod(true); ;
            MethodAttributes methodAccess = baseSetter.Attributes & MethodAttributes.MemberAccessMask;
            
            string cannotSetException = System.Data.Entity.Strings.EntityProxyTypeInfo_CannotSetEntityCollectionProperty(propertyBuilder.Name, typeBuilder.Name);
            MethodBuilder setterBuilder = typeBuilder.DefineMethod("set_" + baseProperty.Name, methodAccess | methodAttributes, null, new Type[] { baseProperty.PropertyType });
            ILGenerator generator = setterBuilder.GetILGenerator();
            Label instanceEqual = generator.DefineLabel();
            generator.Emit(OpCodes.Ldarg_1);
            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Call, _getRelationshipManager);
            generator.Emit(OpCodes.Ldstr, navProperty.RelationshipType.FullName);
            generator.Emit(OpCodes.Ldstr, navProperty.ToEndMember.Name);
            generator.Emit(OpCodes.Callvirt, s_GetRelatedEnd);
            generator.Emit(OpCodes.Beq_S, instanceEqual);
            generator.Emit(OpCodes.Ldstr, cannotSetException);
            generator.Emit(OpCodes.Newobj, s_InvalidOperationConstructor);
            generator.Emit(OpCodes.Throw);
            generator.MarkLabel(instanceEqual);
            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Ldarg_1);
            generator.Emit(OpCodes.Call, baseProperty.GetSetMethod(true));
            generator.Emit(OpCodes.Ret);
            propertyBuilder.SetSetMethod(setterBuilder);

            _collectionProperties.Add(new KeyValuePair<NavigationProperty, PropertyInfo>(navProperty, baseProperty));
        }