/// <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); }
/// <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())); } } }
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()); }
/// <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()); }
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); }
/// <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())); } } }
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); }
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); }
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); }
/// <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)); }