示例#1
0
        /// <summary>
        /// Get or create a client EDM type instance.
        /// </summary>
        /// <param name="type">type to wrap</param>
        /// <returns>client type</returns>
        internal IEdmType GetOrCreateEdmType(Type type)
        {
            EdmTypeCacheValue cachedEdmValue = this.GetOrCreateEdmTypeInternal(type);
            IEdmType          edmType        = cachedEdmValue.EdmType;

            if (edmType.TypeKind == EdmTypeKind.Complex || edmType.TypeKind == EdmTypeKind.Entity)
            {
                bool?hasProperties = cachedEdmValue.HasProperties;
                if (!hasProperties.HasValue)
                {
                    hasProperties = ClientTypeUtil.GetPropertiesOnType(type, /*declaredOnly*/ false).Any();

                    lock (this.clrToEdmTypeCache)
                    {
                        EdmTypeCacheValue existing = this.clrToEdmTypeCache[type];
                        existing.HasProperties = hasProperties;
                    }
                }

                if (hasProperties == false)
                {
                    throw c.Error.InvalidOperation(c.Strings.ClientType_NoSettableFields(type.ToString()));
                }
            }

            return(edmType);
        }
示例#2
0
        /// <summary>
        /// Throw if the given complex type has no properties.
        /// </summary>
        /// <param name="type">The type in question</param>
        /// <param name="cachedEdmType">The EdmTypeCacheValue of the type in question.</param>
        private void ValidateComplexTypeHasProperties(Type type, EdmTypeCacheValue cachedEdmType)
        {
            Debug.Assert(cachedEdmType != null, "cachedEdmType != null");

            // Note that if the type is an entity type, it has at least the key properties, thus there is no need to validate it here.
            if (cachedEdmType.EdmType.TypeKind == EdmTypeKind.Complex)
            {
                bool?hasProperties = cachedEdmType.HasProperties;
                if (!hasProperties.HasValue)
                {
                    hasProperties = ClientTypeUtil.GetPropertiesOnType(type, /*declaredOnly*/ false).Any();

                    lock (this.clrToEdmTypeCache)
                    {
                        EdmTypeCacheValue existing = this.clrToEdmTypeCache[type];
                        existing.HasProperties = hasProperties;
                    }
                }

                if (hasProperties == false)
                {
                    throw c.Error.InvalidOperation(c.Strings.ClientType_NoSettableFields(type.ToString()));
                }
            }
        }
示例#3
0
        private static Type[] GetTypeHierarchy(Type type, out PropertyInfo[] keyProperties, out bool hasProperties)
        {
            keyProperties = ClientTypeUtil.GetKeyPropertiesOnType(type, out hasProperties);
            List <Type> list = new List <Type>();

            if (keyProperties != null)
            {
                Type declaringType;
                if (keyProperties.Length > 0)
                {
                    declaringType = keyProperties[0].DeclaringType;
                }
                else
                {
                    declaringType = type;
                    while (!declaringType.GetCustomAttributes(false).OfType <DataServiceEntityAttribute>().Any <DataServiceEntityAttribute>() && (declaringType.GetBaseType() != null))
                    {
                        declaringType = declaringType.GetBaseType();
                    }
                }
                do
                {
                    list.Insert(0, type);
                }while ((type != declaringType) && ((type = type.GetBaseType()) != null));
            }
            else
            {
                do
                {
                    list.Insert(0, type);
                }while (((type = type.GetBaseType()) != null) && ClientTypeUtil.GetPropertiesOnType(type, false).Any <PropertyInfo>());
            }
            return(list.ToArray());
        }
示例#4
0
        /// <summary>Returns <paramref name="type"/> and its base types, in the order of most base type first and <paramref name="type"/> last.</summary>
        /// <param name="type">Type instance in question.</param>
        /// <param name="keyProperties">Returns the list of key properties if <paramref name="type"/> is an entity type; null otherwise.</param>
        /// <param name="hasProperties">true if <paramref name="type"/> has any (declared or inherited) properties; otherwise false.</param>
        /// <returns>Returns <paramref name="type"/> and its base types, in the order of most base type first and <paramref name="type"/> last.</returns>
        private static Type[] GetTypeHierarchy(Type type, out PropertyInfo[] keyProperties, out bool hasProperties)
        {
            Debug.Assert(type != null, "type != null");

            keyProperties = ClientTypeUtil.GetKeyPropertiesOnType(type, out hasProperties);

            List <Type> hierarchy = new List <Type>();

            if (keyProperties != null)
            {
                // type is an entity. Return all types between keyPropertyDeclaredType and type inclusive.
                Type baseEntityType;
                if (keyProperties.Length > 0)
                {
                    baseEntityType = keyProperties[0].DeclaringType;
                }
                else
                {
                    // Find the type where the DataServiceEntityAttribute is declared on.
                    baseEntityType = type;
                    Debug.Assert(type.GetCustomAttributes(true).OfType <EntityTypeAttribute>().Any(), "type.GetCustomAttributes(true).OfType<DataServiceEntityAttribute>().Any()");
                    while (!baseEntityType.GetCustomAttributes(false).OfType <EntityTypeAttribute>().Any() && c.PlatformHelper.GetBaseType(baseEntityType) != null)
                    {
                        baseEntityType = c.PlatformHelper.GetBaseType(baseEntityType);
                    }

                    Debug.Assert(baseEntityType != null, "keyPropertyDeclaringType != null");
                }

                do
                {
                    hierarchy.Insert(0, type);
                }while (type != baseEntityType && (type = c.PlatformHelper.GetBaseType(type)) != null);
            }
            else
            {
                // type is a complex type. Return all types on the hierarchy where there are properties defined.
                do
                {
                    hierarchy.Insert(0, type);
                }while ((type = c.PlatformHelper.GetBaseType(type)) != null && ClientTypeUtil.GetPropertiesOnType(type, false /*declaredOnly*/).Any());
            }

            return(hierarchy.ToArray());
        }
示例#5
0
        internal IEdmType GetOrCreateEdmType(Type type)
        {
            EdmTypeCacheValue orCreateEdmTypeInternal = this.GetOrCreateEdmTypeInternal(type);
            IEdmType          edmType = orCreateEdmTypeInternal.EdmType;

            if ((edmType.TypeKind == EdmTypeKind.Complex) || (edmType.TypeKind == EdmTypeKind.Entity))
            {
                bool?hasProperties = orCreateEdmTypeInternal.HasProperties;
                if (!hasProperties.HasValue)
                {
                    hasProperties = new bool?(ClientTypeUtil.GetPropertiesOnType(type, false).Any <PropertyInfo>());
                    lock (this.clrToEdmTypeCache)
                    {
                        EdmTypeCacheValue value3 = this.clrToEdmTypeCache[type];
                        value3.HasProperties = hasProperties;
                    }
                }
                if (hasProperties == false)
                {
                    throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.ClientType_NoSettableFields(type.ToString()));
                }
            }
            return(edmType);
        }
示例#6
0
        /// <summary>
        /// Throw if the given complex type has no properties.
        /// </summary>
        /// <param name="type">The type in question</param>
        /// <param name="cachedEdmType">The EdmTypeCacheValue of the type in question.</param>
        private void ValidateComplexType(Type type, EdmTypeCacheValue cachedEdmType)
        {
            Debug.Assert(cachedEdmType != null, "cachedEdmType != null");

            if (cachedEdmType.EdmType.TypeKind == EdmTypeKind.Complex)
            {
                bool?hasProperties = cachedEdmType.HasProperties;
                if (!hasProperties.HasValue)
                {
                    hasProperties = ClientTypeUtil.GetPropertiesOnType(type, /*declaredOnly*/ false).Any();

                    lock (this.clrToEdmTypeCache)
                    {
                        EdmTypeCacheValue existing = this.clrToEdmTypeCache[type];
                        existing.HasProperties = hasProperties;
                    }
                }

                if (hasProperties == false && (type == typeof(System.Object) || type.IsGenericType()))
                {
                    throw c.Error.InvalidOperation(c.Strings.ClientType_NoSettableFields(type.ToString()));
                }
            }
        }
示例#7
0
        private EdmTypeCacheValue GetOrCreateEdmTypeInternal(IEdmStructuredType edmBaseType, Type type, PropertyInfo[] keyProperties, bool isEntity, bool?hasProperties)
        {
            Debug.Assert(type != null, "type != null");
            Debug.Assert(keyProperties != null, "keyProperties != null");

            EdmTypeCacheValue cachedEdmType;

            lock (this.clrToEdmTypeCache)
            {
                this.clrToEdmTypeCache.TryGetValue(type, out cachedEdmType);
            }

            if (cachedEdmType == null)
            {
                Type collectionType;
                if (PrimitiveType.IsKnownNullableType(type))
                {
                    PrimitiveType primitiveType;
                    PrimitiveType.TryGetPrimitiveType(type, out primitiveType);
                    Debug.Assert(primitiveType != null, "primitiveType != null");
                    cachedEdmType = new EdmTypeCacheValue(primitiveType.CreateEdmPrimitiveType(), hasProperties);
                }
                else if ((collectionType = ClientTypeUtil.GetImplementationType(type, typeof(ICollection <>))) != null && ClientTypeUtil.GetImplementationType(type, typeof(IDictionary <,>)) == null)
                {
                    // Collection Type
                    Type     elementType = collectionType.GetGenericArguments()[0];
                    IEdmType itemType    = this.GetOrCreateEdmType(elementType);

                    // Note that
                    // 1. throw here because collection of a collection is not allowed
                    // 2. will also throw during SaveChanges(), validated by unit test case 'SerializationOfCollection'in CollectionTests.cs.
                    if ((itemType.TypeKind == EdmTypeKind.Collection))
                    {
                        throw new ODataException(Strings.ClientType_CollectionOfCollectionNotSupported);
                    }

                    cachedEdmType = new EdmTypeCacheValue(new EdmCollectionType(itemType.ToEdmTypeReference(ClientTypeUtil.CanAssignNull(elementType))), hasProperties);
                }
                else
                {
                    Type enumTypeTmp = null;
                    if (isEntity)
                    {
                        Action <EdmEntityTypeWithDelayLoadedProperties> delayLoadEntityProperties = (entityType) =>
                        {
                            // Create properties without modifying the entityType.
                            // This will leave entityType intact in case of an exception during loading.
                            List <IEdmProperty>           loadedProperties    = new List <IEdmProperty>();
                            List <IEdmStructuralProperty> loadedKeyProperties = new List <IEdmStructuralProperty>();
                            foreach (PropertyInfo property in ClientTypeUtil.GetPropertiesOnType(type, /*declaredOnly*/ edmBaseType != null).OrderBy(p => p.Name))
                            {
                                IEdmProperty edmProperty = this.CreateEdmProperty((EdmStructuredType)entityType, property);
                                loadedProperties.Add(edmProperty);

                                if (edmBaseType == null && keyProperties.Any(k => k.DeclaringType == type && k.Name == property.Name))
                                {
                                    Debug.Assert(edmProperty.PropertyKind == EdmPropertyKind.Structural, "edmProperty.PropertyKind == EdmPropertyKind.Structural");
                                    Debug.Assert(edmProperty.Type.TypeKind() == EdmTypeKind.Primitive, "edmProperty.Type.TypeKind() == EdmTypeKind.Primitive");
                                    loadedKeyProperties.Add((IEdmStructuralProperty)edmProperty);
                                }
                            }

                            // Now add properties to the entityType.
                            foreach (IEdmProperty property in loadedProperties)
                            {
                                entityType.AddProperty(property);
                            }

                            entityType.AddKeys(loadedKeyProperties);
                        };

                        // Creating an entity type
                        Debug.Assert(edmBaseType == null || edmBaseType.TypeKind == EdmTypeKind.Entity, "baseType == null || baseType.TypeKind == EdmTypeKind.Entity");
                        bool hasStream = GetHasStreamValue((IEdmEntityType)edmBaseType, type);
                        cachedEdmType = new EdmTypeCacheValue(
                            new EdmEntityTypeWithDelayLoadedProperties(CommonUtil.GetModelTypeNamespace(type), CommonUtil.GetModelTypeName(type), (IEdmEntityType)edmBaseType, c.PlatformHelper.IsAbstract(type), /*isOpen*/ false, hasStream, delayLoadEntityProperties),
                            hasProperties);
                    }
                    else if ((enumTypeTmp = Nullable.GetUnderlyingType(type) ?? type) != null &&
                             enumTypeTmp.IsEnum())
                    {
                        Action <EdmEnumTypeWithDelayLoadedMembers> delayLoadEnumMembers = (enumType) =>
                        {
#if WINRT
                            foreach (FieldInfo tmp in enumTypeTmp.GetFields().Where(fieldInfo => fieldInfo.IsStatic))
#else
                            foreach (FieldInfo tmp in enumTypeTmp.GetFields(BindingFlags.Static | BindingFlags.Public))
#endif
                            {
                                object memberValue = Enum.Parse(enumTypeTmp, tmp.Name, false);
                                enumType.AddMember(new EdmEnumMember(enumType, tmp.Name, new EdmIntegerConstant((long)Convert.ChangeType(memberValue, typeof(long), CultureInfo.InvariantCulture.NumberFormat))));
                            }
                        };

                        // underlying type may be Edm.Byte, Edm.SByte, Edm.Int16, Edm.Int32, or Edm.Int64.
                        Type underlyingType = Enum.GetUnderlyingType(enumTypeTmp);
                        IEdmPrimitiveType underlyingEdmType = (IEdmPrimitiveType)EdmCoreModel.Instance.FindDeclaredType("Edm." + underlyingType.Name);
                        Debug.Assert(underlyingEdmType != null, "underlyingEdmType != null");
                        bool isFlags = enumTypeTmp.GetCustomAttributes(false).Any(s => s is FlagsAttribute);
                        cachedEdmType = new EdmTypeCacheValue(
                            new EdmEnumTypeWithDelayLoadedMembers(CommonUtil.GetModelTypeNamespace(enumTypeTmp), CommonUtil.GetModelTypeName(enumTypeTmp), underlyingEdmType, isFlags, delayLoadEnumMembers),
                            null);
                    }
                    else
                    {
                        Action <EdmComplexTypeWithDelayLoadedProperties> delayLoadComplexProperties = (complexType) =>
                        {
                            // Create properties without modifying the complexType.
                            // This will leave complexType intact in case of an exception during loading.
                            List <IEdmProperty> loadedProperties = new List <IEdmProperty>();
                            foreach (PropertyInfo property in ClientTypeUtil.GetPropertiesOnType(type, /*declaredOnly*/ edmBaseType != null).OrderBy(p => p.Name))
                            {
                                IEdmProperty edmProperty = this.CreateEdmProperty(complexType, property);
                                loadedProperties.Add(edmProperty);
                            }

                            // Now add properties to the complexType.
                            foreach (IEdmProperty property in loadedProperties)
                            {
                                complexType.AddProperty(property);
                            }
                        };

                        // Creating a complex type
                        Debug.Assert(edmBaseType == null || edmBaseType.TypeKind == EdmTypeKind.Complex, "baseType == null || baseType.TypeKind == EdmTypeKind.Complex");
                        cachedEdmType = new EdmTypeCacheValue(
                            new EdmComplexTypeWithDelayLoadedProperties(CommonUtil.GetModelTypeNamespace(type), CommonUtil.GetModelTypeName(type), (IEdmComplexType)edmBaseType, c.PlatformHelper.IsAbstract(type), /*isOpen*/ false, delayLoadComplexProperties),
                            hasProperties);
                    }
                }

                Debug.Assert(cachedEdmType != null, "cachedEdmType != null");

                IEdmType             edmType = cachedEdmType.EdmType;
                ClientTypeAnnotation clientTypeAnnotation = this.GetOrCreateClientTypeAnnotation(edmType, type);
                this.SetClientTypeAnnotation(edmType, clientTypeAnnotation);

                if (edmType.TypeKind == EdmTypeKind.Entity || edmType.TypeKind == EdmTypeKind.Complex)
                {
                    IEdmStructuredType edmStructuredType = edmType as IEdmStructuredType;
                    Debug.Assert(edmStructuredType != null, "edmStructuredType != null");
                    this.SetMimeTypeForProperties(edmStructuredType);
                }

                // Need to cache the type before loading the properties so we don't stack overflow because
                // loading the property can trigger calls to GetOrCreateEdmType on the same type.
                lock (this.clrToEdmTypeCache)
                {
                    EdmTypeCacheValue existing;
                    if (this.clrToEdmTypeCache.TryGetValue(type, out existing))
                    {
                        cachedEdmType = existing;
                    }
                    else
                    {
                        this.clrToEdmTypeCache.Add(type, cachedEdmType);
                    }
                }
            }

            return(cachedEdmType);
        }
示例#8
0
        private EdmTypeCacheValue GetOrCreateEdmTypeInternal(IEdmStructuredType edmBaseType, Type type, PropertyInfo[] keyProperties, bool isEntity, bool?hasProperties)
        {
            EdmTypeCacheValue value2;
            Action <MetadataProviderEdmEntityType>  action3 = null;
            Action <MetadataProviderEdmComplexType> action4 = null;

            lock (this.clrToEdmTypeCache)
            {
                this.clrToEdmTypeCache.TryGetValue(type, out value2);
            }
            if (value2 == null)
            {
                if (PrimitiveType.IsKnownNullableType(type))
                {
                    PrimitiveType type3;
                    PrimitiveType.TryGetPrimitiveType(type, out type3);
                    value2 = new EdmTypeCacheValue(type3.CreateEdmPrimitiveType(), hasProperties);
                }
                else
                {
                    Type type2;
                    if (((type2 = ClientTypeUtil.GetImplementationType(type, typeof(ICollection <>))) != null) && (ClientTypeUtil.GetImplementationType(type, typeof(IDictionary <,>)) == null))
                    {
                        Type type4 = type2.GetGenericArguments()[0];
                        value2 = new EdmTypeCacheValue(new EdmCollectionType(this.GetOrCreateEdmTypeInternal(type4).EdmType.ToEdmTypeReference(ClientTypeUtil.CanAssignNull(type4))), hasProperties);
                    }
                    else if (isEntity)
                    {
                        if (action3 == null)
                        {
                            action3 = delegate(MetadataProviderEdmEntityType entityType) {
                                List <IEdmProperty>           list  = new List <IEdmProperty>();
                                List <IEdmStructuralProperty> list1 = new List <IEdmStructuralProperty>();
                                using (IEnumerator <PropertyInfo> enumerator = (from p in ClientTypeUtil.GetPropertiesOnType(type, edmBaseType != null)
                                                                                orderby p.Name
                                                                                select p).GetEnumerator())
                                {
                                    Func <PropertyInfo, bool> predicate = null;
                                    while (enumerator.MoveNext())
                                    {
                                        PropertyInfo property = enumerator.Current;
                                        IEdmProperty item     = this.CreateEdmProperty(entityType, property);
                                        list.Add(item);
                                        if (edmBaseType == null)
                                        {
                                            if (predicate == null)
                                            {
                                                predicate = k => (k.DeclaringType == type) && (k.Name == property.Name);
                                            }
                                            if (keyProperties.Any <PropertyInfo>(predicate))
                                            {
                                                list1.Add((IEdmStructuralProperty)item);
                                            }
                                        }
                                    }
                                }
                                foreach (IEdmProperty property2 in list)
                                {
                                    entityType.AddProperty(property2);
                                }
                                entityType.AddKeys(list1);
                            };
                        }
                        Action <MetadataProviderEdmEntityType> propertyLoadAction = action3;
                        value2 = new EdmTypeCacheValue(new MetadataProviderEdmEntityType(CommonUtil.GetModelTypeNamespace(type), CommonUtil.GetModelTypeName(type), (IEdmEntityType)edmBaseType, type.IsAbstract(), false, propertyLoadAction), hasProperties);
                    }
                    else
                    {
                        if (action4 == null)
                        {
                            action4 = delegate(MetadataProviderEdmComplexType complexType) {
                                List <IEdmProperty> list = new List <IEdmProperty>();
                                foreach (PropertyInfo info in from p in ClientTypeUtil.GetPropertiesOnType(type, edmBaseType != null)
                                         orderby p.Name
                                         select p)
                                {
                                    IEdmProperty item = this.CreateEdmProperty(complexType, info);
                                    list.Add(item);
                                }
                                foreach (IEdmProperty property2 in list)
                                {
                                    complexType.AddProperty(property2);
                                }
                            };
                        }
                        Action <MetadataProviderEdmComplexType> action2 = action4;
                        value2 = new EdmTypeCacheValue(new MetadataProviderEdmComplexType(CommonUtil.GetModelTypeNamespace(type), CommonUtil.GetModelTypeName(type), (IEdmComplexType)edmBaseType, type.IsAbstract(), action2), hasProperties);
                    }
                }
                IEdmType             edmType = value2.EdmType;
                ClientTypeAnnotation orCreateClientTypeAnnotation = this.GetOrCreateClientTypeAnnotation(edmType, type);
                edmType.SetClientTypeAnnotation(orCreateClientTypeAnnotation);
                if ((edmType.TypeKind == EdmTypeKind.Entity) || (edmType.TypeKind == EdmTypeKind.Complex))
                {
                    IEdmStructuredType edmStructuredType = edmType as IEdmStructuredType;
                    this.SetMimeTypeForProperties(edmStructuredType);
                }
                lock (this.clrToEdmTypeCache)
                {
                    EdmTypeCacheValue value3;
                    if (this.clrToEdmTypeCache.TryGetValue(type, out value3))
                    {
                        return(value3);
                    }
                    this.clrToEdmTypeCache.Add(type, value2);
                }
            }
            return(value2);
        }
示例#9
0
        private EdmTypeCacheValue GetOrCreateEdmTypeInternal(IEdmStructuredType edmBaseType, Type type, PropertyInfo[] keyProperties, bool isEntity, bool?hasProperties)
        {
            Debug.Assert(type != null, "type != null");
            Debug.Assert(keyProperties != null, "keyProperties != null");

            EdmTypeCacheValue cachedEdmType;

            lock (this.clrToEdmTypeCache)
            {
                this.clrToEdmTypeCache.TryGetValue(type, out cachedEdmType);
            }

            if (cachedEdmType == null)
            {
                Type collectionType;
                if (PrimitiveType.IsKnownNullableType(type))
                {
                    PrimitiveType primitiveType;
                    PrimitiveType.TryGetPrimitiveType(type, out primitiveType);
                    Debug.Assert(primitiveType != null, "primitiveType != null");
                    cachedEdmType = new EdmTypeCacheValue(primitiveType.CreateEdmPrimitiveType(), hasProperties);
                }
                else if ((collectionType = ClientTypeUtil.GetImplementationType(type, typeof(ICollection <>))) != null && ClientTypeUtil.GetImplementationType(type, typeof(IDictionary <,>)) == null)
                {
                    // Collection Type
                    Type     elementType = collectionType.GetGenericArguments()[0];
                    IEdmType itemType    = this.GetOrCreateEdmTypeInternal(elementType).EdmType;

                    // Note that while collection of a collection is not allowed, we cannot throw here since it's a breaking change.
                    // We will throw during SaveChanges() and we have unit test validating the error case.
                    Debug.Assert(
                        itemType.TypeKind == EdmTypeKind.Entity || itemType.TypeKind == EdmTypeKind.Complex || itemType.TypeKind == EdmTypeKind.Primitive || itemType.TypeKind == EdmTypeKind.Collection,
                        "itemType.TypeKind == EdmTypeKind.Entity || itemType.TypeKind == EdmTypeKind.Complex || itemType.TypeKind == EdmTypeKind.Primitive || itemType.TypeKind == EdmTypeKind.Collection");

                    cachedEdmType = new EdmTypeCacheValue(new EdmCollectionType(itemType.ToEdmTypeReference(ClientTypeUtil.CanAssignNull(elementType))), hasProperties);
                }
                else
                {
                    if (isEntity)
                    {
                        Action <EdmEntityTypeWithDelayLoadedProperties> delayLoadEntityProperties = (entityType) =>
                        {
                            // Create properties without modifying the entityType.
                            // This will leave entityType intact in case of an exception during loading.
                            List <IEdmProperty>           loadedProperties    = new List <IEdmProperty>();
                            List <IEdmStructuralProperty> loadedKeyProperties = new List <IEdmStructuralProperty>();
                            foreach (PropertyInfo property in ClientTypeUtil.GetPropertiesOnType(type, /*declaredOnly*/ edmBaseType != null).OrderBy(p => p.Name))
                            {
                                IEdmProperty edmProperty = this.CreateEdmProperty((EdmStructuredType)entityType, property);
                                loadedProperties.Add(edmProperty);

                                if (edmBaseType == null && keyProperties.Any(k => k.DeclaringType == type && k.Name == property.Name))
                                {
                                    Debug.Assert(edmProperty.PropertyKind == EdmPropertyKind.Structural, "edmProperty.PropertyKind == EdmPropertyKind.Structural");
                                    Debug.Assert(edmProperty.Type.TypeKind() == EdmTypeKind.Primitive, "edmProperty.Type.TypeKind() == EdmTypeKind.Primitive");
                                    loadedKeyProperties.Add((IEdmStructuralProperty)edmProperty);
                                }
                            }

                            // Now add properties to the entityType.
                            foreach (IEdmProperty property in loadedProperties)
                            {
                                entityType.AddProperty(property);
                            }

                            entityType.AddKeys(loadedKeyProperties);
                        };

                        // Creating an entity type
                        Debug.Assert(edmBaseType == null || edmBaseType.TypeKind == EdmTypeKind.Entity, "baseType == null || baseType.TypeKind == EdmTypeKind.Entity");
                        cachedEdmType = new EdmTypeCacheValue(
                            new EdmEntityTypeWithDelayLoadedProperties(CommonUtil.GetModelTypeNamespace(type), CommonUtil.GetModelTypeName(type), (IEdmEntityType)edmBaseType, c.PlatformHelper.IsAbstract(type), false /*isOpen*/, delayLoadEntityProperties),
                            hasProperties);
                    }
                    else
                    {
                        Action <EdmComplexTypeWithDelayLoadedProperties> delayLoadComplexProperties = (complexType) =>
                        {
                            // Create properties without modifying the complexType.
                            // This will leave complexType intact in case of an exception during loading.
                            List <IEdmProperty> loadedProperties = new List <IEdmProperty>();
                            foreach (PropertyInfo property in ClientTypeUtil.GetPropertiesOnType(type, /*declaredOnly*/ edmBaseType != null).OrderBy(p => p.Name))
                            {
                                IEdmProperty edmProperty = this.CreateEdmProperty(complexType, property);
                                loadedProperties.Add(edmProperty);
                            }

                            // Now add properties to the complexType.
                            foreach (IEdmProperty property in loadedProperties)
                            {
                                complexType.AddProperty(property);
                            }
                        };

                        // Creating a complex type
                        Debug.Assert(edmBaseType == null || edmBaseType.TypeKind == EdmTypeKind.Complex, "baseType == null || baseType.TypeKind == EdmTypeKind.Complex");
                        cachedEdmType = new EdmTypeCacheValue(
                            new EdmComplexTypeWithDelayLoadedProperties(CommonUtil.GetModelTypeNamespace(type), CommonUtil.GetModelTypeName(type), (IEdmComplexType)edmBaseType, c.PlatformHelper.IsAbstract(type), delayLoadComplexProperties),
                            hasProperties);
                    }
                }

                Debug.Assert(cachedEdmType != null, "cachedEdmType != null");

                IEdmType             edmType = cachedEdmType.EdmType;
                ClientTypeAnnotation clientTypeAnnotation = this.GetOrCreateClientTypeAnnotation(edmType, type);
                this.SetClientTypeAnnotation(edmType, clientTypeAnnotation);

                if (edmType.TypeKind == EdmTypeKind.Entity || edmType.TypeKind == EdmTypeKind.Complex)
                {
                    IEdmStructuredType edmStructuredType = edmType as IEdmStructuredType;
                    Debug.Assert(edmStructuredType != null, "edmStructuredType != null");
                    this.SetMimeTypeForProperties(edmStructuredType);
                }

                // Need to cache the type before loading the properties so we don't stack overflow because
                // loading the property can trigger calls to GetOrCreateEdmType on the same type.
                lock (this.clrToEdmTypeCache)
                {
                    EdmTypeCacheValue existing;
                    if (this.clrToEdmTypeCache.TryGetValue(type, out existing))
                    {
                        cachedEdmType = existing;
                    }
                    else
                    {
                        this.clrToEdmTypeCache.Add(type, cachedEdmType);
                    }
                }
            }

            return(cachedEdmType);
        }
示例#10
0
        /// <summary>
        /// Returns the list of key properties defined on <paramref name="type"/>; null if <paramref name="type"/> is complex.
        /// </summary>
        /// <param name="type">Type in question.</param>
        /// <param name="hasProperties">true if <paramref name="type"/> has any (declared or inherited) properties; otherwise false.</param>
        /// <returns>Returns the list of key properties defined on <paramref name="type"/>; null if <paramref name="type"/> is complex.</returns>
        internal static PropertyInfo[] GetKeyPropertiesOnType(Type type, out bool hasProperties)
        {
            if (CommonUtil.IsUnsupportedType(type))
            {
                throw new InvalidOperationException(c.Strings.ClientType_UnsupportedType(type));
            }

            string typeName = type.ToString();
            IEnumerable <object> customAttributes       = type.GetCustomAttributes(true);
            bool                isEntity                = customAttributes.OfType <EntityTypeAttribute>().Any();
            KeyAttribute        dataServiceKeyAttribute = customAttributes.OfType <KeyAttribute>().FirstOrDefault();
            List <PropertyInfo> keyProperties           = new List <PropertyInfo>();

            PropertyInfo[] properties = ClientTypeUtil.GetPropertiesOnType(type, false /*declaredOnly*/).ToArray();

            hasProperties = properties.Length > 0;
            KeyKind currentKeyKind = KeyKind.NotKey;
            KeyKind newKeyKind     = KeyKind.NotKey;

            foreach (PropertyInfo propertyInfo in properties)
            {
                if ((newKeyKind = ClientTypeUtil.IsKeyProperty(propertyInfo, dataServiceKeyAttribute)) != KeyKind.NotKey)
                {
                    if (newKeyKind > currentKeyKind)
                    {
                        keyProperties.Clear();
                        currentKeyKind = newKeyKind;
                        keyProperties.Add(propertyInfo);
                    }
                    else if (newKeyKind == currentKeyKind)
                    {
                        keyProperties.Add(propertyInfo);
                    }
                }
            }

            Type keyPropertyDeclaringType = null;

            foreach (PropertyInfo key in keyProperties)
            {
                if (keyPropertyDeclaringType == null)
                {
                    keyPropertyDeclaringType = key.DeclaringType;
                }
                else if (keyPropertyDeclaringType != key.DeclaringType)
                {
                    throw c.Error.InvalidOperation(c.Strings.ClientType_KeysOnDifferentDeclaredType(typeName));
                }

                if (!PrimitiveType.IsKnownType(key.PropertyType) && !(key.PropertyType.GetGenericTypeDefinition() == typeof(System.Nullable <>) && key.PropertyType.GetGenericArguments().First().IsEnum()))
                {
                    throw c.Error.InvalidOperation(c.Strings.ClientType_KeysMustBeSimpleTypes(key.Name, typeName, key.PropertyType.FullName));
                }
            }

            if (dataServiceKeyAttribute != null)
            {
                if (newKeyKind == KeyKind.AttributedKey && keyProperties.Count != dataServiceKeyAttribute?.KeyNames.Count)
                {
                    var m = (from string a in dataServiceKeyAttribute.KeyNames
                             where (from b in properties
                                    where b.Name == a
                                    select b).FirstOrDefault() == null
                             select a).First <string>();
                    throw c.Error.InvalidOperation(c.Strings.ClientType_MissingProperty(typeName, m));
                }
            }

            return(keyProperties.Count > 0 ? keyProperties.ToArray() : (isEntity ? ClientTypeUtil.EmptyPropertyInfoArray : null));
        }