/// <summary>
        /// Populates the member metadata for the given type
        /// </summary>
        /// <param name="resourceTypeCacheItem">Instance of ResourceTypeCacheItem containing the ResourceType and its metadata.</param>
        /// <param name="workspace">workspace containing the metadata information</param>
        /// <param name="metadataCacheItem">Instance of ProviderMetadataCacheItem.</param>
        /// <param name="primitiveResourceTypeMap">Map of primitive types to use when building member metadata.</param>
        internal static void PopulateMemberMetadata(
            ResourceTypeCacheItem resourceTypeCacheItem,
            IProviderMetadata workspace,
            ProviderMetadataCacheItem metadataCacheItem,
            PrimitiveResourceTypeMap primitiveResourceTypeMap)
        {
            Debug.Assert(resourceTypeCacheItem != null, "resourceTypeCacheItem != null");
            Debug.Assert(workspace != null, "workspace != null");

            var resourceType = resourceTypeCacheItem.ResourceType;

            // Find the type from the OSpace
            IProviderType edmType = workspace.GetProviderType(resourceType.FullName);
            foreach (IProviderMember member in edmType.Members)
            {
                ResourcePropertyKind kind = (ResourcePropertyKind)(-1);

                // ObjectContextServiceProvider fails with NullReferenceException when an entity property is not public.
                // If the property on the CLR type which is representing the EDM type has non-public properties but those properties are part of the
                // conceptual model, the server will try to load CLR metadata for these properties.
                // The Type.GetProperty(propertyName) method used BindingFlags.Instance | BindingFlags.Public by default if no binding flags are specified.
                // Since the property was not found with these binding flags, the GetProperty method returns null, which we didn't check for in v1 and v2 and threw an NRE.
                // We now check for null return values from this function and throw if we find that the model property declared on the CLR type is not public.
                PropertyInfo propertyInfo = resourceType.InstanceType.GetProperty(member.Name, BindingFlags.Instance | BindingFlags.Public);
                if (propertyInfo == null)
                {
                    throw new DataServiceException((int)HttpStatusCode.InternalServerError, Strings.ObjectContext_PublicPropertyNotDefinedOnType(edmType.Name, member.Name));
                }

                ResourceType propertyType = null;
                switch (member.EdmTypeKind)
                {
                    case BuiltInTypeKind.PrimitiveType:
#if !INTERNAL_DROP && !EFRTM
                        Type propertyClrType = ObjectContextSpatialUtil.IsDbGeography(propertyInfo.PropertyType) ? typeof(Geography) : propertyInfo.PropertyType;
#else
                        Type propertyClrType = propertyInfo.PropertyType;
#endif
                        propertyType = primitiveResourceTypeMap.GetPrimitive(propertyClrType);

                        if (propertyType == null)
                        {
                            throw new NotSupportedException(Strings.ObjectContext_PrimitiveTypeNotSupported(member.Name, edmType.Name, member.EdmTypeName));
                        }

                        if (member.IsKey)
                        {
                            kind = ResourcePropertyKind.Key | ResourcePropertyKind.Primitive;
                        }
                        else
                        {
                            kind = ResourcePropertyKind.Primitive;
                        }

                        break;
                    case BuiltInTypeKind.ComplexType:
                        kind = ResourcePropertyKind.ComplexType;
                        propertyType = metadataCacheItem.TryGetResourceType(propertyInfo.PropertyType);
                        break;
                    case BuiltInTypeKind.EntityType:
                        kind = ResourcePropertyKind.ResourceReference;
                        propertyType = metadataCacheItem.TryGetResourceType(propertyInfo.PropertyType);
                        break;
                    case BuiltInTypeKind.CollectionType:
                        kind = ResourcePropertyKind.ResourceSetReference;
                        Type collectionItemClrType = workspace.GetClrType(member.CollectionItemType);
                        Debug.Assert(!WebUtil.IsPrimitiveType(collectionItemClrType), "We don't support collections of primitives, we shouldn't see one here");
                        propertyType = metadataCacheItem.TryGetResourceType(collectionItemClrType);
                        break;
                    default:
                        throw new NotSupportedException(Strings.ObjectContext_PrimitiveTypeNotSupported(member.Name, edmType.Name, member.EdmTypeName));
                }

                Debug.Assert(propertyType != null, "propertyType != null");
                ResourceProperty resourceProperty = new ResourceProperty(propertyInfo.Name, kind, propertyType);
                SetMimeTypeForMappedMember(resourceProperty, member);
                resourceType.AddProperty(resourceProperty);
#if !EF6Provider
                ObjectContextServiceProvider.PopulateFacets(resourceProperty, member.Facets, resourceProperty.ResourceType.ResourceTypeKind == ResourceTypeKind.EntityType /*ignoreNullableAnnotation*/);
                ObjectContextServiceProvider.PopulateAnnotations(member.MetadataProperties, resourceProperty.AddCustomAnnotation);
#endif
                resourceTypeCacheItem.AddResourcePropertyCacheItem(resourceProperty, new ObjectContextResourcePropertyCacheItem(propertyInfo, member));
            }
        }
        /// <summary>
        /// Populates metadata from the given object context
        /// </summary>
        /// <param name="metadataCacheItem">Instance of ProviderMetadataCacheItem in which metadata needs to be populated.</param>
        protected sealed override void PopulateMetadata(ProviderMetadataCacheItem metadataCacheItem)
        {
            Debug.Assert(metadataCacheItem != null, "metadataCacheItem != null");
            Debug.Assert(this.ObjectContext != null, "this.ObjectContext != null");

            InitializeObjectItemCollection(this.ObjectContext, this.DataSourceType.Assembly);
            MetadataWorkspace metadataWorkspace = this.ObjectContext.MetadataWorkspace;

            // Create Resource types for all the top level entity types and complexTypes
            foreach (StructuralType edmType in metadataWorkspace.GetItems<StructuralType>(DataSpace.CSpace))
            {
                if (edmType.BuiltInTypeKind == BuiltInTypeKind.EntityType ||
                    edmType.BuiltInTypeKind == BuiltInTypeKind.ComplexType)
                {
                    // Populates metadata for the given types and all its base types
                    if (PopulateTypeMetadata(metadataWorkspace, edmType, metadataCacheItem) == null)
                    {
                        this.typesWithoutOSpaceMetadata.Add(edmType);
                    }
                }
            }

            foreach (EntityContainer entityContainer in metadataWorkspace.GetItems<EntityContainer>(DataSpace.CSpace))
            {
                bool defaultEntityContainer = entityContainer.Name == this.ObjectContext.DefaultContainerName;

                // Get the list of entity sets (Ignore the relationship sets, since we won't allow that to be queried directly
                foreach (EntitySetBase entitySetBase in entityContainer.BaseEntitySets)
                {
                    // Ignore all the association sets for the type being, since we are caching only entity sets
                    if (entitySetBase.BuiltInTypeKind != BuiltInTypeKind.EntitySet)
                    {
                        continue;
                    }

                    EntitySet entitySet = (EntitySet)entitySetBase;
                    Type elementType = GetClrTypeForCSpaceType(metadataWorkspace, entitySet.ElementType);
                    ResourceType resourceType;
                    if (elementType == null || (resourceType = metadataCacheItem.TryGetResourceType(elementType)) == null)
                    {
                        throw new InvalidOperationException(Strings.ObjectContextServiceProvider_OSpaceTypeNotFound(entitySet.ElementType.FullName));
                    }

                    string entitySetName = GetEntitySetName(entitySet.Name, entitySet.EntityContainer.Name, defaultEntityContainer);
                    ResourceSet resourceSet = new ResourceSet(entitySetName, resourceType);
                    metadataCacheItem.EntitySets.Add(entitySetName, resourceSet);
#if !EF6Provider
                    resourceSet.EntityContainerName = entityContainer.Name;
                    ObjectContextServiceProvider.PopulateAnnotations(entitySetBase.MetadataProperties, resourceSet.AddCustomAnnotation);
#endif
                    metadataCacheItem.QueryRootCache.Add(resourceSet, this.BuildQueryRootDelegate(resourceSet));
                }
            }

            // Now go and populate the member information for each resource type
            foreach (var resourceTypeCacheItem in metadataCacheItem.ResourceTypeCacheItems)
            {
                var resourceType = resourceTypeCacheItem.ResourceType;

                if (resourceType.ResourceTypeKind == ResourceTypeKind.Primitive)
                {
                    continue;
                }

                PopulateMemberMetadata(resourceTypeCacheItem, new ObjectContextMetadata(metadataWorkspace), metadataCacheItem, PrimitiveResourceTypeMap.TypeMap);
            }
        }
        /// <summary>
        /// Populates the metadata for the given type and its base type
        /// </summary>
        /// <param name="workspace">metadata workspace containing all the metadata information</param>
        /// <param name="edmType"> type whose metadata needs to be populated </param>
        /// <param name="metadataCacheItem">Instance of ProviderMetadataCacheItem.</param>
        /// <returns>returns the resource type corresponding to the given edmType</returns>
        private static ResourceType PopulateTypeMetadata(
            MetadataWorkspace workspace,
            StructuralType edmType,
            ProviderMetadataCacheItem metadataCacheItem)
        {
            Debug.Assert(
                edmType.BuiltInTypeKind == BuiltInTypeKind.EntityType ||
                edmType.BuiltInTypeKind == BuiltInTypeKind.ComplexType,
                "type must be entity or complex type");

            ResourceType resourceType = null;
            Type clrType = GetClrTypeForCSpaceType(workspace, edmType);
            if (clrType != null)
            {
                resourceType = metadataCacheItem.TryGetResourceType(clrType);
                if (resourceType == null)
                {
                    ResourceType baseType = null;
                    if (edmType.BaseType != null)
                    {
                        baseType = PopulateTypeMetadata(workspace, (StructuralType)edmType.BaseType, metadataCacheItem);
                    }

                    resourceType = CreateResourceType(edmType, clrType, baseType, metadataCacheItem);
                }
            }

            return resourceType;
        }
        /// <summary>
        /// Creates a new instance of resource type given the cspace structural type and mapping clr type.
        /// </summary>
        /// <param name="cspaceType">cspace structural type.</param>
        /// <param name="clrType">mapping clr type for the given structural type.</param>
        /// <param name="baseResourceType">the base resource type for the given resource type.</param>
        /// <param name="metadataCacheItem">Instance of ProviderMetadataCacheItem.</param>
        /// <returns>the new resource type instance created for the given cspace type.</returns>
        private static ResourceType CreateResourceType(
            StructuralType cspaceType,
            Type clrType,
            ResourceType baseResourceType,
            ProviderMetadataCacheItem metadataCacheItem)
        {
            ResourceTypeKind resourceTypeKind = cspaceType.BuiltInTypeKind == BuiltInTypeKind.EntityType ? ResourceTypeKind.EntityType : ResourceTypeKind.ComplexType;

            // We do not support open types in Object Context provider yet.
            ResourceType resourceType = new ResourceType(clrType, resourceTypeKind, baseResourceType, cspaceType.NamespaceName, cspaceType.Name, clrType.IsAbstract);
            if (GetEntityTypeDefaultStreamProperty(cspaceType))
            {
                resourceType.IsMediaLinkEntry = true;
            }

            // Add stream properties that are marked NamedStream in clrType to resourceType.
            AddStreamProperties(resourceType, clrType, baseResourceType == null);

            metadataCacheItem.AddResourceType(clrType, resourceType);
            var childTypes = metadataCacheItem.ChildTypesCache;
            childTypes.Add(resourceType, null);
            if (baseResourceType != null)
            {
                Debug.Assert(childTypes.ContainsKey(baseResourceType), "childTypes.ContainsKey(baseResourceType)");
                if (childTypes[baseResourceType] == null)
                {
                    childTypes[baseResourceType] = new List<ResourceType>();
                }

                childTypes[baseResourceType].Add(resourceType);
            }

#if !EF6Provider
            ObjectContextServiceProvider.PopulateAnnotations(cspaceType.MetadataProperties, resourceType.AddCustomAnnotation);
#endif
            return resourceType;
        }
 /// <summary>
 /// Populate metadata for the given clr type.
 /// </summary>
 /// <param name="type">type whose metadata needs to be loaded.</param>
 /// <param name="metadataCacheItem">Instance of ProviderMetadataCacheItem.</param>
 /// <returns>resource type containing metadata for the given clr type.</returns>
 protected abstract ResourceType PopulateMetadataForType(Type type, ProviderMetadataCacheItem metadataCacheItem);
        /// <summary>
        /// Populate types for metadata specified by the provider
        /// </summary>
        /// <param name="userSpecifiedTypes">list of types specified by the provider</param>
        /// <param name="metadataCacheItem">Instance of ProviderMetadataCacheItem.</param>
        protected sealed override void PopulateMetadataForUserSpecifiedTypes(
            IEnumerable<Type> userSpecifiedTypes,
            ProviderMetadataCacheItem metadataCacheItem)
        {
            Queue<ResourceType> unvisitedTypes = new Queue<ResourceType>();
            foreach (Type type in userSpecifiedTypes)
            {
                ResourceType resourceType;
                if (TryGetType(metadataCacheItem, type, out resourceType))
                {
                    continue;
                }

                if (IsEntityOrComplexType(type, metadataCacheItem, unvisitedTypes) == null)
                {
                    throw new InvalidOperationException(Strings.BadProvider_InvalidTypeSpecified(type.FullName));
                }
            }

            PopulateMetadataForTypes(metadataCacheItem, unvisitedTypes);
        }
        /// <summary>
        /// Find out all the derived types in the list of assemblies and then populate metadata for those types
        /// </summary>
        /// <param name="metadataCacheItem">Instance of ProviderMetadataCacheItem.</param>
        /// <param name="unvisitedTypes">list of unvisited types</param>
        private static void PopulateMetadataForDerivedTypes(
            ProviderMetadataCacheItem metadataCacheItem,
            Queue<ResourceType> unvisitedTypes)
        {
            Debug.Assert(metadataCacheItem != null, "metadataCacheItem != null");
            Debug.Assert(unvisitedTypes != null, "unvisitedTypes != null");

            // Find all the root resource entity types
            List<ResourceType> rootTypes = new List<ResourceType>();

            // To find the list of derived types, we should use the types
            // referred by the sets as the base type, to make sure we are
            // loading metadata only for types that can be referenced by
            // the given sets.
            foreach (ResourceSet resourceSet in metadataCacheItem.EntitySets.Values)
            {
                rootTypes.Add(resourceSet.ResourceType);
            }

            // Use the default comparer, which calls Assembly.Equals (not a simple reference comparison).
            HashSet<Assembly> assemblies = new HashSet<Assembly>(EqualityComparer<Assembly>.Default);
            List<Type> derivedTypes = new List<Type>();

            // Walk through all the types in the assemblies and find all the derived types
            foreach (var resourceTypeCacheItem in metadataCacheItem.ResourceTypeCacheItems)
            {
                var resourceType = resourceTypeCacheItem.ResourceType;

                // No need to look into primitive types, as these live in system assemblies.
                if (resourceType.ResourceTypeKind == ResourceTypeKind.Primitive)
                {
                    continue;
                }

                Assembly assembly = resourceType.InstanceType.Assembly;
                //// ignore if the assembly has already been scanned
                if (assemblies.Contains(assembly))
                {
                    continue;
                }

                // Walk all the types in that assembly
                foreach (Type type in assembly.GetTypes())
                {
                    // skip all the non visible types or types which have generic parameters
                    if (!type.IsVisible || HasGenericParameters(type))
                    {
                        continue;
                    }

                    // Skip the type if its already loaded
                    if (metadataCacheItem.TryGetResourceType(type) != null)
                    {
                        continue;
                    }

                    // Check if this type dervies from any one of the root types
                    for (int i = 0; i < rootTypes.Count; i++)
                    {
                        if (rootTypes[i].InstanceType.IsAssignableFrom(type))
                        {
                            derivedTypes.Add(type);
                        }
                    }
                }

                assemblies.Add(assembly);
            }

            foreach (Type type in derivedTypes)
            {
                BuildHierarchyForEntityType(type, metadataCacheItem, unvisitedTypes, false /* entityTypeCandidate */);
                PopulateMetadataForTypes(metadataCacheItem, unvisitedTypes);
            }
        }
 /// <summary>
 /// Populates the metadata for the given provider
 /// </summary>
 /// <param name="metadataCacheItem">Instance of ProviderMetadataCacheItem in which metadata needs to be populated.</param>
 protected abstract void PopulateMetadata(ProviderMetadataCacheItem metadataCacheItem);
        private static void BuildTypeProperties(
            ResourceType parentResourceType,
            ProviderMetadataCacheItem metadataCacheItem,
            Queue<ResourceType> unvisitedTypes)
        {
            Debug.Assert(parentResourceType != null, "parentResourceType != null");
            Debug.Assert(metadataCacheItem != null, "metadataCacheItem != null");
            Debug.Assert(unvisitedTypes != null, "unvisitedTypes != null");

            BindingFlags bindingFlags = WebUtil.PublicInstanceBindingFlags;

            // For non root types, we should only look for properties that are declared for this type
            if (parentResourceType.BaseType != null)
            {
                bindingFlags = bindingFlags | BindingFlags.DeclaredOnly;
            }

            HashSet<string> propertiesToBeIgnored = new HashSet<string>(IgnorePropertiesAttribute.GetProperties(parentResourceType.InstanceType, false /*inherit*/, bindingFlags), StringComparer.Ordinal);
            Debug.Assert(parentResourceType.IsOpenType == false, "ReflectionServiceProvider does not support Open types.");

            HashSet<string> etagPropertyNames = new HashSet<string>(LoadETagProperties(parentResourceType), StringComparer.Ordinal);

            ResourceKeyKind keyKind = (ResourceKeyKind)Int32.MaxValue;
            PropertyInfo[] properties = parentResourceType.InstanceType.GetProperties(bindingFlags);

            // Should not allow System.Object on server
            // The general fix for this bug is to not support any resource type that doesn't have
            // any publically visible properties, including System.object and also custom types which don't have any properties.
            if (!properties.Any() && parentResourceType.BaseType == null)
            {
                throw new NotSupportedException(Strings.ReflectionProvider_ResourceTypeHasNoPublicallyVisibleProperties(parentResourceType.FullName));
            }

            foreach (PropertyInfo property in properties)
            {
                // Ignore the properties which are specified in the IgnoreProperties attribute
                if (propertiesToBeIgnored.Contains(property.Name))
                {
                    continue;
                }

                if (property.CanRead && property.GetIndexParameters().Length == 0)
                {
                    ResourcePropertyKind kind = (ResourcePropertyKind)(-1);
                    ResourceType resourceType;
                    Type resourcePropertyType = property.PropertyType;
                    bool collection = false;

                    if (!TryGetType(metadataCacheItem, resourcePropertyType, out resourceType))
                    {
                        Type collectionType = GetIEnumerableElement(property.PropertyType);
                        if (collectionType != null)
                        {
                            TryGetType(metadataCacheItem, collectionType, out resourceType);

                            // Even if the above method returns false, we should set the
                            // following variable appropriately, so that we can use them below
                            collection = true;
                            resourcePropertyType = collectionType;
                        }
                    }

                    if (resourceType != null)
                    {
                        #region Already Known Type
                        if (resourceType.ResourceTypeKind == ResourceTypeKind.Primitive)
                        {
                            if (collection)
                            {
                                // If it's a collection it can't be a key property (we don't allow collection properties as key)
                                kind = ResourcePropertyKind.Collection;
                            }
                            else
                            {
                                ResourceKeyKind currentKeyKind;
                                if (parentResourceType.BaseType == null && parentResourceType.ResourceTypeKind == ResourceTypeKind.EntityType && IsPropertyKeyProperty(property, out currentKeyKind))
                                {
                                    // Check for key property only on root types, since keys must be defined on the root types
                                    if ((int)currentKeyKind < (int)keyKind)
                                    {
                                        if (parentResourceType.KeyProperties.Count != 0)
                                        {
                                            // Remove the existing property as key property - mark it as non key property
                                            parentResourceType.RemoveKeyProperties();
                                        }

                                        keyKind = currentKeyKind;
                                        kind = ResourcePropertyKind.Key | ResourcePropertyKind.Primitive;
                                    }
                                    else if ((int)currentKeyKind == (int)keyKind)
                                    {
                                        Debug.Assert(currentKeyKind == ResourceKeyKind.AttributedKey, "This is the only way of specifying composite keys");
                                        kind = ResourcePropertyKind.Key | ResourcePropertyKind.Primitive;
                                    }
                                    else
                                    {
                                        kind = ResourcePropertyKind.Primitive;
                                    }
                                }
                                else
                                {
                                    kind = ResourcePropertyKind.Primitive;
                                }
                            }
                        }
                        else if (resourceType.ResourceTypeKind == ResourceTypeKind.ComplexType)
                        {
                            kind = collection ? ResourcePropertyKind.Collection : ResourcePropertyKind.ComplexType;
                        }
                        else if (resourceType.ResourceTypeKind == ResourceTypeKind.EntityType)
                        {
                            kind = collection ? ResourcePropertyKind.ResourceSetReference : ResourcePropertyKind.ResourceReference;
                        }
                        #endregion // Already Known Type
                    }
                    else
                    {
                        resourceType = IsEntityOrComplexType(resourcePropertyType, metadataCacheItem, unvisitedTypes);
                        if (resourceType != null)
                        {
                            if (resourceType.ResourceTypeKind == ResourceTypeKind.ComplexType)
                            {
                                if (collection)
                                {
                                    // For backward compat reasons only look closely on the item type if the property is a collection (IEnumerable<T>) 
                                    // and the T looks like a complex type.
                                    // In that case we used to only allow entity types as T, now with collection properties we also allow primitive and complex types,
                                    //   but we must explicitely disallow collection of collection, that is any T which implements IEnumerable<T>.
                                    // Note that we can't just make IEnumerable<T> not be a complex types since in certain cases we used to recognize it as such
                                    //   and we would break those cases. One example is user registered known types.
                                    Type collectionType = GetIEnumerableElement(resourcePropertyType);
                                    if (collectionType != null)
                                    {
                                        throw new InvalidOperationException(Strings.ReflectionProvider_CollectionOfCollectionProperty(property.Name, parentResourceType.FullName));
                                    }

                                    kind = ResourcePropertyKind.Collection;
                                }
                                else
                                {
                                    kind = ResourcePropertyKind.ComplexType;
                                }
                            }
                            else
                            {
                                Debug.Assert(resourceType.ResourceTypeKind == ResourceTypeKind.EntityType, "Must be an entity type");
                                kind = collection ? ResourcePropertyKind.ResourceSetReference : ResourcePropertyKind.ResourceReference;
                            }
                        }
                    }

                    // if resource type is null OR
                    // if complex type has a property of entity type
                    if (resourceType == null ||
                        (resourceType.ResourceTypeKind == ResourceTypeKind.EntityType && parentResourceType.ResourceTypeKind == ResourceTypeKind.ComplexType))
                    {
                        if (resourceType == null)
                        {
                            // Provide a better error message for collection of collection
                            if (collection && GetIEnumerableElement(resourcePropertyType) != null)
                            {
                                throw new InvalidOperationException(Strings.ReflectionProvider_CollectionOfCollectionProperty(property.Name, parentResourceType.FullName));
                            }

                            // Provide a better error message for collection of wrong types
                            if (collection)
                            {
                                throw new InvalidOperationException(Strings.ReflectionProvider_CollectionOfUnsupportedTypeProperty(property.Name, parentResourceType.FullName, resourcePropertyType));
                            }

                            if (CommonUtil.IsUnsupportedType(resourcePropertyType))
                            {
                                throw new InvalidOperationException(Strings.BadProvider_UnsupportedPropertyType(property.Name, parentResourceType.FullName));
                            }

                            throw new InvalidOperationException(Strings.ReflectionProvider_InvalidProperty(property.Name, parentResourceType.FullName));
                        }

                        // Navigation property on a complex type is not supported
                        throw new InvalidOperationException(Strings.ReflectionProvider_ComplexTypeWithNavigationProperty(property.Name, parentResourceType.FullName));
                    }

                    if (resourceType.ResourceTypeKind == ResourceTypeKind.EntityType)
                    {
                        ResourceSet container = InternalGetContainerForResourceType(resourcePropertyType, metadataCacheItem.EntitySets.Values);
                        if (container == null)
                        {
                            throw new InvalidOperationException(Strings.ReflectionProvider_EntityPropertyWithNoEntitySet(parentResourceType.FullName, property.Name));
                        }
                    }

                    if (kind == ResourcePropertyKind.Collection)
                    {
                        // Collection properties need the collection type (representing the IEnumerable<> part).
                        resourceType = ResourceType.GetCollectionResourceType(resourceType);
                    }

                    if (etagPropertyNames.Remove(property.Name))
                    {
                        kind |= ResourcePropertyKind.ETag;
                    }

                    ResourceProperty resourceProperty = new ResourceProperty(property.Name, kind, resourceType);
                    MimeTypeAttribute attribute = BaseServiceProvider.GetMimeTypeAttribute(property);
                    if (attribute != null)
                    {
                        resourceProperty.MimeType = attribute.MimeType;
                    }

                    parentResourceType.AddProperty(resourceProperty);
                }
                else
                {
                    throw new InvalidOperationException(Strings.ReflectionProvider_InvalidProperty(property.Name, parentResourceType.FullName));
                }
            }

            if (parentResourceType.ResourceTypeKind == ResourceTypeKind.EntityType &&
                (parentResourceType.KeyProperties == null || parentResourceType.KeyProperties.Count == 0))
            {
                throw new InvalidOperationException(Strings.ReflectionProvider_KeyPropertiesCannotBeIgnored(parentResourceType.FullName));
            }

            if (etagPropertyNames.Count != 0)
            {
                throw new InvalidOperationException(Strings.ReflectionProvider_ETagPropertyNameNotValid(etagPropertyNames.ElementAt(0), parentResourceType.FullName));
            }
        }
        /// <summary>
        /// If the given type is a entity or complex type, it returns the resource type corresponding to the given type
        /// </summary>
        /// <param name="type">clr type</param>
        /// <param name="metadataCacheItem">Instance of ProviderMetadataCacheItem.</param>
        /// <param name="unvisitedTypes">list of unvisited types</param>
        /// <returns>resource type corresponding to the given clr type, if the clr type is entity or complex</returns>
        private static ResourceType IsEntityOrComplexType(
            Type type,
            ProviderMetadataCacheItem metadataCacheItem,
            Queue<ResourceType> unvisitedTypes)
        {
            // Ignore values types here. We do not support resources of values type (entity or complex)
            if (type.IsValueType || CommonUtil.IsUnsupportedType(type))
            {
                return null;
            }

            ResourceType resourceType = BuildHierarchyForEntityType(type, metadataCacheItem, unvisitedTypes, false /* entityTypeCandidate */);
            if (resourceType == null && IsComplexType(type))
            {
                resourceType = ReflectionServiceProvider.CreateResourceType(type, ResourceTypeKind.ComplexType, null, metadataCacheItem);
                unvisitedTypes.Enqueue(resourceType);
            }

            return resourceType;
        }
        /// <summary>
        /// Walks through the list of ancestors and finds the root base type and collects metadata for the entire chain of ancestors
        /// </summary>
        /// <param name="type">type whose ancestors metadata needs to be populated</param>
        /// <param name="metadataCacheItem">Instance of ProviderMetadataCacheItem.</param>
        /// <param name="unvisitedTypes">list of unvisited types</param>
        /// <param name="entityTypeCandidate">Whether <paramref name="type"/> is a candidate to be an entity type.</param>
        /// <returns>return true if this given type is a entity type, otherwise returns false</returns>
        private static ResourceType BuildHierarchyForEntityType(
            Type type,
            ProviderMetadataCacheItem metadataCacheItem,
            Queue<ResourceType> unvisitedTypes,
            bool entityTypeCandidate)
        {
            List<Type> ancestors = new List<Type>();

            if (!type.IsVisible)
            {
                return null;
            }

            if (CommonUtil.IsUnsupportedType(type))
            {
                // deriving from an unsupported type is not allowed
                throw new InvalidOperationException(Strings.BadProvider_UnsupportedType(type.FullName));
            }

            Type baseType = type;
            ResourceType baseResourceType = null;

            // Since this method is also used on property types, which can be interfaces,
            // Base types can be null
            while (baseType != null)
            {
                // Try and check if the base type is already loaded
                if (TryGetType(metadataCacheItem, baseType, out baseResourceType))
                {
                    break;
                }

                ancestors.Add(baseType);
                baseType = baseType.BaseType;
            }

            if (baseResourceType == null)
            {
                // If entityTypeCandidate is false, then it means that the current type can't
                // be a entity type with keys. In other words, it must derive from an existing
                // type. Otherwise, its not an entity type
                if (entityTypeCandidate == false)
                {
                    return null;
                }

                // Find the last ancestor which has key defined
                for (int i = ancestors.Count - 1; i >= 0; i--)
                {
                    if (CommonUtil.IsUnsupportedType(ancestors[i]))
                    {
                        // deriving from an unsupported type is not allowed
                        throw new InvalidOperationException(Strings.BadProvider_UnsupportedAncestorType(type.FullName, ancestors[i].FullName));
                    }

                    if (DoesTypeHaveKeyProperties(ancestors[i], entityTypeCandidate))
                    {
                        break;
                    }

                    // Else this type is not interesting. Remove it from the ancestors list
                    ancestors.RemoveAt(i);
                }
            }
            else if (baseResourceType.ResourceTypeKind != ResourceTypeKind.EntityType)
            {
                return null;
            }
            else if (ancestors.Count == 0)
            {
                // we might have found the top level element.So just return
                return baseResourceType;
            }

            // For all the valid ancestors, add the type to the list of types encountered 
            // and unvisited types
            // its important that we enqueue the ancestors first, since when we populate member metadata
            // we can make sure that the base type is fully populated
            for (int i = ancestors.Count - 1; i >= 0; i--)
            {
                ResourceType entityType = ReflectionServiceProvider.CreateResourceType(ancestors[i], ResourceTypeKind.EntityType, baseResourceType, metadataCacheItem);
                unvisitedTypes.Enqueue(entityType);
                baseResourceType = entityType;
            }

            return baseResourceType;
        }
        /// <summary>
        /// Populates the metadata for the given unvisited types and all the associated types with this type
        /// </summary>
        /// <param name="metadataCacheItem">Instance of ProviderMetadataCacheItem.</param>
        /// <param name="unvisitedTypes">list of unvisited type</param>
        private static void PopulateMetadataForTypes(
            ProviderMetadataCacheItem metadataCacheItem,
            Queue<ResourceType> unvisitedTypes)
        {
            Debug.Assert(metadataCacheItem != null, "metadataCacheItem != null");
            Debug.Assert(unvisitedTypes != null, "unvisitedTypes != null");

            // Start walking down all the types
            while (unvisitedTypes.Count != 0)
            {
                // get the unvisited element
                ResourceType type = unvisitedTypes.Dequeue();

                // Go through all the properties and find out one or more complex types
                BuildTypeProperties(type, metadataCacheItem, unvisitedTypes);
            }
        }
        /// <summary>
        /// Populate metadata for the given clr type.
        /// </summary>
        /// <param name="type">type whose metadata needs to be loaded.</param>
        /// <param name="metadataCacheItem">Instance of ProviderMetadataCacheItem.</param>
        /// <returns>resource type containing metadata for the given clr type.</returns>
        protected sealed override ResourceType PopulateMetadataForType(
            Type type,
            ProviderMetadataCacheItem metadataCacheItem)
        {
            Queue<ResourceType> unvisitedTypes = new Queue<ResourceType>();
            ResourceType resourceType;
            if (!TryGetType(metadataCacheItem, type, out resourceType))
            {
                resourceType = IsEntityOrComplexType(type, metadataCacheItem, unvisitedTypes);
                if (resourceType != null)
                {
                    PopulateMetadataForTypes(metadataCacheItem, unvisitedTypes);
                }
            }

            return resourceType;
        }
        /// <summary>
        /// Looks up the metadata in the cache. If not present in the cache, then loads metadata from the provider.
        /// </summary>
        /// <param name="skipServiceOperations">Should service operations be loaded.</param>
        internal void LoadMetadata(bool skipServiceOperations)
        {
            Type dataServiceType = this.dataServiceInstance.GetType();
            Type dataSourceType = this.dataSourceInstance.GetType();

            // If 2 threads enter at the same time, and none of them find the metadata (since its the first time),
            // both of them will load new metadata and try to add them to the cache. But the cache is thread safe, hence
            // before adding, it will check again and return if there is an existing metadata. If it is, we should discard the
            // metadata that just got initialized and use one from the cache.
            this.metadata = MetadataCache<ProviderMetadataCacheItem>.TryLookup(dataServiceType, this.dataSourceInstance);
            if (this.metadata == null)
            {
                this.metadata = new ProviderMetadataCacheItem(dataSourceType);

                // Populate metadata in provider.
                this.PopulateMetadata(this.metadata);

                // Populate service operations only on-demand.
                if (!skipServiceOperations)
                {
                    this.LoadServiceOperations();
                }

                this.metadataRequiresInitialization = true;

                // no need to add metadata yet in the cache, since there might be some encountered while applying
                // configuration or while making it read-only.
            }
        }
        /// <summary>
        /// returns the new resource type instance
        /// </summary>
        /// <param name="type">backing clr type for the resource.</param>
        /// <param name="kind">kind of the resource.</param>
        /// <param name="baseType">base type of the resource.</param>
        /// <param name="metadataCacheItem">Instance of ProviderMetadataCacheItem.</param>
        /// <returns>returns a new instance of the resource type containing all the metadata.</returns>
        private static ResourceType CreateResourceType(
            Type type,
            ResourceTypeKind kind,
            ResourceType baseType,
            ProviderMetadataCacheItem metadataCacheItem)
        {
            ResourceType resourceType = new ResourceType(type, kind, baseType, type.Namespace, CommonUtil.GetModelTypeName(type), type.IsAbstract);
            resourceType.IsOpenType = false;

            // We need to look at inherited attributes as well so we pass true for inherit argument. 
            if (type.GetCustomAttributes(typeof(HasStreamAttribute), true /* inherit */).Length == 1)
            {
                resourceType.IsMediaLinkEntry = true;
            }

            // Add stream properties that are marked NamedStream in clrType to resourceType.
            AddStreamProperties(resourceType, type, baseType == null);

            metadataCacheItem.AddResourceType(type, resourceType);
            var childTypes = metadataCacheItem.ChildTypesCache;
            childTypes.Add(resourceType, null);
            if (baseType != null)
            {
                Debug.Assert(childTypes.ContainsKey(baseType), "childTypes.ContainsKey(baseType)");
                if (childTypes[baseType] == null)
                {
                    childTypes[baseType] = new List<ResourceType>();
                }

                childTypes[baseType].Add(resourceType);
            }

            return resourceType;
        }
        /// <summary>
        /// Find the corresponding ResourceType for a given Type, primitive or not
        /// </summary>
        /// <param name="metadataCacheItem">Instance of ProviderMetadataCacheItem.</param>
        /// <param name="type">Type to look for</param>
        /// <param name="resourceType">Corresponding ResourceType, if found</param>
        /// <returns>True if type found, false otherwise</returns>
        protected static bool TryGetType(ProviderMetadataCacheItem metadataCacheItem, Type type, out ResourceType resourceType)
        {
            Debug.Assert(metadataCacheItem != null, "metadataCacheItem != null");
            Debug.Assert(type != null, "type != null");

            resourceType = PrimitiveResourceTypeMap.TypeMap.GetPrimitive(type);

            if (resourceType == null)
            {
                resourceType = metadataCacheItem.TryGetResourceType(type);
            }

            return resourceType != null;
        }
        /// <summary>
        /// Populate types for metadata specified by the provider
        /// </summary>
        /// <param name="userSpecifiedTypes">list of types specified by the provider</param>
        /// <param name="metadataCacheItem">Instance of ProviderMetadataCacheItem.</param>
        protected sealed override void PopulateMetadataForUserSpecifiedTypes(
            IEnumerable<Type> userSpecifiedTypes,
            ProviderMetadataCacheItem metadataCacheItem)
        {
            foreach (Type type in userSpecifiedTypes)
            {
                if (this.PopulateMetadataForType(type, metadataCacheItem) == null)
                {
                    throw new InvalidOperationException(Strings.BadProvider_InvalidTypeSpecified(type.FullName));
                }
            }

            // If there is a type in the model, for which we couldn't load the metadata, we should throw.
            if (this.typesWithoutOSpaceMetadata.Count != 0)
            {
                throw new InvalidOperationException(Strings.ObjectContext_UnableToLoadMetadataForType(this.typesWithoutOSpaceMetadata[0].FullName));
            }

            this.typesWithoutOSpaceMetadata = null;
        }
 /// <summary>
 /// Populate types for metadata specified by the provider
 /// </summary>
 /// <param name="userSpecifiedTypes">list of types specified by the provider</param>
 /// <param name="metadataCacheItem">Instance of ProviderMetadataCacheItem.</param>
 protected abstract void PopulateMetadataForUserSpecifiedTypes(IEnumerable<Type> userSpecifiedTypes, ProviderMetadataCacheItem metadataCacheItem);
        /// <summary>
        /// Populate metadata for the given clr type.
        /// </summary>
        /// <param name="type">type whose metadata needs to be loaded.</param>
        /// <param name="metadataCacheItem">Instance of ProviderMetadataCacheItem.</param>
        /// <returns>resource type containing metadata for the given clr type.</returns>
        protected sealed override ResourceType PopulateMetadataForType(Type type, ProviderMetadataCacheItem metadataCacheItem)
        {
            Debug.Assert(!WebUtil.IsPrimitiveType(type), "Why are we trying to load metadata for a primitive type?");

            ResourceType resourceType = metadataCacheItem.TryGetResourceType(type);
            if (resourceType == null)
            {
                InitializeObjectItemCollection(this.ObjectContext, type.Assembly);
                ObjectItemCollection objectItemCollection = (ObjectItemCollection)this.ObjectContext.MetadataWorkspace.GetItemCollection(DataSpace.OSpace);
                StructuralType ospaceType, cspaceType;
                if (objectItemCollection.TryGetItem<StructuralType>(type.FullName, out ospaceType))
                {
                    if (this.ObjectContext.MetadataWorkspace.TryGetEdmSpaceType(ospaceType, out cspaceType))
                    {
                        ResourceType baseType = null;
                        if (cspaceType.BaseType != null)
                        {
                            baseType = this.PopulateMetadataForType(type.BaseType, metadataCacheItem);
                        }

                        resourceType = CreateResourceType(cspaceType, type, baseType, metadataCacheItem);
                        this.typesWithoutOSpaceMetadata.Remove(cspaceType);
                    }
                }
            }

            return resourceType;
        }
        /// <summary>Make all the metadata readonly</summary>
        private void MakeMetadataReadonly()
        {
            Debug.Assert(this.metadataRequiresInitialization, "Should only call when initializing metadata.");

            foreach (ResourceSet container in this.ResourceSets)
            {
                container.SetReadOnly();
            }

            foreach (ResourceType resourceType in this.Types)
            {
                resourceType.SetReadOnly();

                // This will cause Properties collection to be initialized and validated.
                resourceType.PropertiesDeclaredOnThisType.Count();
            }

            foreach (ServiceOperation operation in this.ServiceOperations)
            {
                operation.SetReadOnly();
            }

            // After metadata has been completely loaded, add it to the cache.
            this.metadata = MetadataCache<ProviderMetadataCacheItem>.AddCacheItem(this.dataServiceInstance.GetType(), this.dataSourceInstance, this.metadata);
        }
        /// <summary>Populates the metadata for this provider.</summary>
        /// <param name="metadataCacheItem">Instance of ProviderMetadataCacheItem in which metadata needs to be populated.</param>
        protected sealed override void PopulateMetadata(ProviderMetadataCacheItem metadataCacheItem)
        {
            Queue<ResourceType> unvisitedTypes = new Queue<ResourceType>();

            // Get the list of properties to be ignored.
            List<string> propertiesToBeIgnored = new List<string>(
                IgnorePropertiesAttribute.GetProperties(this.DataSourceType, true /*inherit*/, WebUtil.PublicInstanceBindingFlags));
            PropertyInfo[] properties = this.DataSourceType.GetProperties(WebUtil.PublicInstanceBindingFlags);
            foreach (PropertyInfo property in properties)
            {
                if (!propertiesToBeIgnored.Contains(property.Name) && property.CanRead && property.GetIndexParameters().Length == 0)
                {
                    Type elementType = BaseServiceProvider.GetIQueryableElement(property.PropertyType);
                    if (elementType != null)
                    {
                        // If the element type has key defined (in itself or one of its ancestors)
                        ResourceType resourceType = BuildHierarchyForEntityType(elementType, metadataCacheItem, unvisitedTypes, true /* entity type candidate */);
                        if (resourceType != null)
                        {
                            // We do not allow MEST scenario for reflection provider
                            foreach (KeyValuePair<string, ResourceSet> entitySetInfo in metadataCacheItem.EntitySets)
                            {
                                Type entitySetType = entitySetInfo.Value.ResourceType.InstanceType;
                                if (entitySetType.IsAssignableFrom(elementType))
                                {
                                    throw new InvalidOperationException(Strings.ReflectionProvider_MultipleEntitySetsForSameType(entitySetInfo.Value.Name, property.Name, entitySetType.FullName, resourceType.FullName));
                                }

                                if (elementType.IsAssignableFrom(entitySetType))
                                {
                                    throw new InvalidOperationException(Strings.ReflectionProvider_MultipleEntitySetsForSameType(property.Name, entitySetInfo.Value.Name, resourceType.FullName, entitySetType.FullName));
                                }
                            }

                            // Add the entity set to the list of entity sets.
                            ResourceSet resourceContainer = new ResourceSet(property.Name, resourceType);
                            metadataCacheItem.EntitySets.Add(property.Name, resourceContainer);
                            metadataCacheItem.QueryRootCache.Add(resourceContainer, this.BuildQueryRootDelegate(resourceContainer));
                        }
                        else
                        {
                            throw new InvalidOperationException(Strings.ReflectionProvider_InvalidEntitySetProperty(property.Name, XmlConvert.EncodeName(((IDataServiceMetadataProvider)this).ContainerName)));
                        }
                    }
                }
            }

            // Populate the metadata for all the types in unvisited types 
            // and also their properties and populates metadata about property types
            PopulateMetadataForTypes(metadataCacheItem, unvisitedTypes);

            // At this point, we should have all the top level entity types and the complex types
            PopulateMetadataForDerivedTypes(metadataCacheItem, unvisitedTypes);
        }