/// <summary>
        /// Adds the given ResourceType to the cache.
        /// </summary>
        /// <param name="type">CLR type.</param>
        /// <param name="resourceType">ResourceType instance.</param>
        internal void AddResourceType(Type type, ResourceType resourceType)
        {
            var cacheItem = new ResourceTypeCacheItem(resourceType);

            this.typeCache.Add(type, cacheItem);
        }
        /// <summary>
        /// Get the PropertyInfo for the given resource property
        /// </summary>
        /// <param name="resourceTypeCacheItem">Instance of ResourceTypeCacheItem containing the ResourceType instance.</param>
        /// <param name="resourceProperty">ResourceProperty instance.</param>
        /// <returns>PropertyInfo instance for the given ResourceProperty.</returns>
        protected ResourcePropertyCacheItem GetResourcePropertyCacheItem(ResourceTypeCacheItem resourceTypeCacheItem, ResourceProperty resourceProperty)
        {
            Debug.Assert(resourceTypeCacheItem.ResourceType.Properties.Contains(resourceProperty), "resourceTypeCacheItem.ResourceType.Properties.Contains(resourceProperty)");
            var declaringResourceType = resourceTypeCacheItem.ResourceType.GetDeclaringTypeForProperty(resourceProperty);
            if (declaringResourceType != resourceTypeCacheItem.ResourceType)
            {
                resourceTypeCacheItem = this.ResolveNonPrimitiveTypeCacheItem(declaringResourceType.InstanceType);
            }

            return resourceTypeCacheItem.GetResourcePropertyCacheItem(resourceProperty);    
        }
        /// <summary>Sets the value of the property.</summary>
        /// <param name="instance">The object whose property needs to be set.</param>
        /// <param name="resourceTypeCacheItem">ResourceTypeCacheItem containing the ResourceType and its metadata representing the instance parameter.</param>
        /// <param name="propertyValue">new value for the property.</param>
        /// <param name="resourceProperty">metadata for the property to be set.</param>
        private void SetValue(object instance, ResourceTypeCacheItem resourceTypeCacheItem, object propertyValue, ResourceProperty resourceProperty)
        {
            Debug.Assert(instance != null, "instance != null");
            Debug.Assert(resourceTypeCacheItem != null, "resourceTypeCacheItem != null");
            Debug.Assert(resourceProperty != null, "resourceProperty != null");

            MethodInfo setMethod = this.GetResourcePropertyCacheItem(resourceTypeCacheItem, resourceProperty).PropertyInfo.GetSetMethod();
            if (setMethod == null)
            {
                throw ObjectContextServiceProvider.CreateBadRequestError(Strings.BadRequest_PropertyValueCannotBeSet(resourceProperty.Name));
            }

            try
            {
                setMethod.Invoke(instance, new object[] { propertyValue });
            }
            catch (TargetInvocationException exception)
            {
                ErrorHandler.HandleTargetInvocationException(exception);
                throw;
            }
            catch (ArgumentException exception)
            {
                throw ObjectContextServiceProvider.CreateBadRequestError(Strings.BadRequest_ErrorInSettingPropertyValue(resourceProperty.Name), exception);
            }
        }
        /// <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>
 /// Adds the given ResourceType to the cache.
 /// </summary>
 /// <param name="type">CLR type.</param>
 /// <param name="resourceType">ResourceType instance.</param>
 internal void AddResourceType(Type type, ResourceType resourceType)
 {
     var cacheItem = new ResourceTypeCacheItem(resourceType);
     this.typeCache.Add(type, cacheItem);
 }