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.
            var 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(
                        Strings.Validator_OSpace_InvalidNavPropReturnType(
                            propertyInfo.Name, propertyInfo.DeclaringType.FullName, propertyInfo.PropertyType.FullName)));
                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

            var attribute = (EdmRelationshipNavigationPropertyAttribute)relationshipPropertyAttributes[0];

            EdmMember member = null;
            EdmType   type;

            if (SessionData.TypesInLoading.TryGetValue(attribute.RelationshipNamespaceName + "." + attribute.RelationshipName, out type)
                &&
                Helper.IsAssociationType(type))
            {
                var relationshipType = (AssociationType)type;
                if (relationshipType != null)
                {
                    // The return value of this property has been verified, so create the property now
                    var navigationProperty = new NavigationProperty(propertyInfo.Name, TypeUsage.Create(propertyType));
                    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(
                                Strings.TargetRoleNameInNavigationPropertyNotValid(
                                    propertyInfo.Name, propertyInfo.DeclaringType.FullName, attribute.TargetRoleName,
                                    attribute.RelationshipName)));
                        member = null;
                    }

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

            if (member != null)
            {
                declaringType.AddMember(member);
            }
        }
        /// <summary>
        ///     Load all the property metadata of the given type
        /// </summary>
        /// <param name="structuralType"> The type where properties are loaded </param>
        private void LoadPropertiesFromType(StructuralType structuralType)
        {
            // Look at both public, internal, and private instanced properties declared at this type, inherited members
            // are not looked at.  Internal and private properties are also looked at because they are also schematized fields
            var properties = structuralType.ClrType.GetProperties(PropertyReflectionBindingFlags);

            foreach (var property in properties)
            {
                EdmMember newMember           = null;
                var       isEntityKeyProperty = false; //used for EdmScalarProperties only

                // 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.
                if (property.IsDefined(typeof(EdmRelationshipNavigationPropertyAttribute), false))
                {
                    // keep the loop var from being lifted
                    var pi = property;
                    _unresolvedNavigationProperties.Add(
                        () =>
                        ResolveNavigationProperty(structuralType, pi));
                }
                else if (property.IsDefined(typeof(EdmScalarPropertyAttribute), false))
                {
                    if ((Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType).IsEnum)
                    {
                        TrackClosure(property.PropertyType);
                        var local = property;
                        AddTypeResolver(() => ResolveEnumTypeProperty(structuralType, local));
                    }
                    else
                    {
                        newMember = LoadScalarProperty(structuralType.ClrType, property, out isEntityKeyProperty);
                    }
                }
                else if (property.IsDefined(typeof(EdmComplexPropertyAttribute), false))
                {
                    TrackClosure(property.PropertyType);
                    // keep loop var from being lifted
                    var local = property;
                    AddTypeResolver(() => ResolveComplexTypeProperty(structuralType, local));
                }

                if (newMember == null)
                {
                    // Property does not have one of the following attributes:
                    //     EdmScalarPropertyAttribute, EdmComplexPropertyAttribute, EdmRelationshipNavigationPropertyAttribute
                    // This means its an unmapped property and can be ignored.
                    // Or there were error encountered while loading the properties
                    continue;
                }

                // Add the property object to the type
                structuralType.AddMember(newMember);

                // Add to the entity's collection of key members
                // Do this here instead of in the if condition above for scalar properties because
                // we want to make sure the AddMember call above did not fail before updating the key members
                if (Helper.IsEntityType(structuralType) && isEntityKeyProperty)
                {
                    ((EntityType)structuralType).AddKeyMember(newMember);
                }
            }
        }
 internal RowType GetKeyRowType()
 {
     if (_keyRow == null)
     {
         var keyProperties = new List<EdmProperty>(KeyMembers.Count);
         keyProperties.AddRange(KeyMembers.Select(keyMember => new EdmProperty(keyMember.Name, Helper.GetModelTypeUsage(keyMember))));
         Interlocked.CompareExchange(ref _keyRow, new RowType(keyProperties), null);
     }
     return _keyRow;
 }
        /// <summary>
        ///     Load metadata of the given type - when you call this method, you should check and make sure that the type has
        ///     edm attribute. If it doesn't,we won't load the type and it will be returned as null
        /// </summary>
        private void LoadType(Type clrType)
        {
            Debug.Assert(clrType.Assembly == SourceAssembly, "Why are we loading a type that is not in our assembly?");
            Debug.Assert(!SessionData.TypesInLoading.ContainsKey(clrType.FullName), "Trying to load a type that is already loaded???");
            Debug.Assert(!clrType.IsGenericType, "Generic type is not supported");

            EdmType edmType = null;

            var typeAttributes = (EdmTypeAttribute[])clrType.GetCustomAttributes(typeof(EdmTypeAttribute), false /*inherit*/);

            // the CLR doesn't allow types to have duplicate/multiple attribute declarations

            if (typeAttributes.Length != 0)
            {
                if (clrType.IsNested)
                {
                    SessionData.EdmItemErrors.Add(
                        new EdmItemError(Strings.NestedClassNotSupported(clrType.FullName, clrType.Assembly.FullName)));
                    return;
                }
                var typeAttribute  = typeAttributes[0];
                var cspaceTypeName = String.IsNullOrEmpty(typeAttribute.Name) ? clrType.Name : typeAttribute.Name;
                if (String.IsNullOrEmpty(typeAttribute.NamespaceName) &&
                    clrType.Namespace == null)
                {
                    SessionData.EdmItemErrors.Add(new EdmItemError(Strings.Validator_TypeHasNoNamespace));
                    return;
                }

                var cspaceNamespaceName = String.IsNullOrEmpty(typeAttribute.NamespaceName)
                                              ? clrType.Namespace
                                              : typeAttribute.NamespaceName;

                if (typeAttribute.GetType()
                    == typeof(EdmEntityTypeAttribute))
                {
                    edmType = new ClrEntityType(clrType, cspaceNamespaceName, cspaceTypeName);
                }
                else if (typeAttribute.GetType()
                         == typeof(EdmComplexTypeAttribute))
                {
                    edmType = new ClrComplexType(clrType, cspaceNamespaceName, cspaceTypeName);
                }
                else
                {
                    Debug.Assert(typeAttribute is EdmEnumTypeAttribute, "Invalid type attribute encountered");

                    // Note that TryGetPrimitiveType() will return false not only for types that are not primitive
                    // but also for CLR primitive types that are valid underlying enum types in CLR but are not
                    // a valid Edm primitive types (e.g. ulong)
                    PrimitiveType underlyingEnumType;
                    if (!ClrProviderManifest.Instance.TryGetPrimitiveType(clrType.GetEnumUnderlyingType(), out underlyingEnumType))
                    {
                        SessionData.EdmItemErrors.Add(
                            new EdmItemError(
                                Strings.Validator_UnsupportedEnumUnderlyingType(clrType.GetEnumUnderlyingType().FullName)));

                        return;
                    }

                    edmType = new ClrEnumType(clrType, cspaceNamespaceName, cspaceTypeName);
                }
            }
            else
            {
                // not a type we are interested
                return;
            }

            Debug.Assert(
                !CacheEntry.ContainsType(edmType.Identity), "This type must not be already present in the list of types for this assembly");
            // Also add this to the list of the types for this assembly
            CacheEntry.TypesInAssembly.Add(edmType);

            // Add this to the known type map so we won't try to load it again
            SessionData.TypesInLoading.Add(clrType.FullName, edmType);

            // Load properties for structural type
            if (Helper.IsStructuralType(edmType))
            {
                //Load base type only for entity type - not sure if we will allow complex type inheritance
                if (Helper.IsEntityType(edmType))
                {
                    TrackClosure(clrType.BaseType);
                    AddTypeResolver(
                        () => edmType.BaseType = ResolveBaseType(clrType.BaseType));
                }

                // Load the properties for this type
                LoadPropertiesFromType((StructuralType)edmType);
            }

            return;
        }
 // <summary>
 // Validates a EdmMember object to determine if it can be added to this type's
 // Members collection. If this method returns without throwing, it is assumed
 // the member is valid.
 // </summary>
 // <param name="member"> The member to validate </param>
 // <exception cref="System.ArgumentException">Thrown if the member is not a EdmProperty</exception>
 internal override void ValidateMemberForAdd(EdmMember member)
 {
     Debug.Assert(
         Helper.IsEdmProperty(member) || Helper.IsNavigationProperty(member),
         "Only members of type Property may be added to Entity types.");
 }