protected static bool MaterializePrimitiveDataValue(Type type, string wireTypeName, object value, System.Data.Services.Client.ResponseInfo responseInfo, Func <string> throwOnNullMessage, out object materializedValue) { PrimitiveType type3; Type clrType = Nullable.GetUnderlyingType(type) ?? type; bool flag = PrimitiveType.TryGetPrimitiveType(clrType, out type3); if (!flag) { flag = PrimitiveType.TryGetPrimitiveType(responseInfo.TypeResolver.ResolveEdmTypeName(type, wireTypeName).ElementType, out type3); } if (flag) { if (value == null) { if (!ClientTypeUtil.CanAssignNull(type)) { throw new InvalidOperationException(throwOnNullMessage()); } materializedValue = null; } else { materializedValue = ConvertPrimitiveValue(value, clrType); } return(true); } materializedValue = null; return(false); }
/// <summary> /// Creates an Edm property. /// </summary> /// <param name="declaringType">Type declaring this property.</param> /// <param name="propertyInfo">PropertyInfo instance for this property.</param> /// <returns>Returns a new instance of Edm property.</returns> private IEdmProperty CreateEdmProperty(IEdmStructuredType declaringType, PropertyInfo propertyInfo) { IEdmType propertyEdmType = this.GetOrCreateEdmType(propertyInfo.PropertyType); Debug.Assert( propertyEdmType.TypeKind == EdmTypeKind.Entity || propertyEdmType.TypeKind == EdmTypeKind.Complex || propertyEdmType.TypeKind == EdmTypeKind.Enum || propertyEdmType.TypeKind == EdmTypeKind.Primitive || propertyEdmType.TypeKind == EdmTypeKind.Collection, "Property kind should be Entity, Complex, Enum, Primitive or Collection."); IEdmProperty edmProperty = null; bool isPropertyNullable = ClientTypeUtil.CanAssignNull(propertyInfo.PropertyType); if (propertyEdmType.TypeKind == EdmTypeKind.Entity || (propertyEdmType.TypeKind == EdmTypeKind.Collection && ((IEdmCollectionType)propertyEdmType).ElementType.TypeKind() == EdmTypeKind.Entity)) { if (declaringType.TypeKind == EdmTypeKind.Entity || declaringType.TypeKind == EdmTypeKind.Complex) { if (declaringType as IEdmEntityType == null && declaringType as IEdmComplexType == null) { throw c.Error.InvalidOperation(c.Strings.ClientTypeCache_NonEntityTypeOrNonComplexTypeCannotContainEntityProperties(propertyInfo.Name, propertyInfo.DeclaringType.ToString())); } // Create a navigation property representing one side of an association. // The partner representing the other side exists only inside this property and is not added to the target entity type, // so it should not cause any name collisions. edmProperty = EdmNavigationProperty.CreateNavigationPropertyWithPartner( ClientTypeUtil.GetServerDefinedName(propertyInfo), propertyEdmType.ToEdmTypeReference(isPropertyNullable), /*dependentProperties*/ null, /*principalProperties*/ null, /*containsTarget*/ false, EdmOnDeleteAction.None, "Partner", declaringType.ToEdmTypeReference(true), /*partnerDependentProperties*/ null, /*partnerPrincipalProperties*/ null, /*partnerContainsTarget*/ false, EdmOnDeleteAction.None); } } else { edmProperty = new EdmStructuralProperty(declaringType, ClientTypeUtil.GetServerDefinedName(propertyInfo), propertyEdmType.ToEdmTypeReference(isPropertyNullable)); } edmProperty.SetClientPropertyAnnotation(new ClientPropertyAnnotation(edmProperty, propertyInfo, this)); return(edmProperty); }
/// <summary>Materializes a primitive value. No op or non-primitive values.</summary> /// <param name="type">Type of value to set.</param> /// <param name="wireTypeName">Type name from the payload.</param> /// <param name="value">Value of primitive provided by ODL.</param> /// <param name="throwOnNullMessage">The exception message if the value is null.</param> /// <param name="materializedValue">The materialized value.</param> private void MaterializePrimitiveDataValue(Type type, string wireTypeName, object value, Func <string> throwOnNullMessage, out object materializedValue) { Debug.Assert(type != null, "type != null"); ClientTypeAnnotation nestedElementType = null; Type underlyingType = Nullable.GetUnderlyingType(type) ?? type; PrimitiveType ptype; bool knownType = PrimitiveType.TryGetPrimitiveType(underlyingType, out ptype); if (!knownType) { nestedElementType = this.context.ResolveTypeForMaterialization(type, wireTypeName); Debug.Assert(nestedElementType != null, "nestedElementType != null -- otherwise ReadTypeAttribute (or someone!) should throw"); knownType = PrimitiveType.TryGetPrimitiveType(nestedElementType.ElementType, out ptype); } if (knownType) { if (value == null) { if (!ClientTypeUtil.CanAssignNull(type)) { throw new InvalidOperationException(throwOnNullMessage()); } materializedValue = null; } else { ODataUntypedValue untypedVal = value as ODataUntypedValue; if ((untypedVal != null) && this.context.UndeclaredPropertyBehavior == UndeclaredPropertyBehavior.Support) { value = CommonUtil.ParseJsonToPrimitiveValue(untypedVal.RawValue); } materializedValue = this.PrimitivePropertyConverter.ConvertPrimitiveValue(value, underlyingType); } } else { materializedValue = null; } }
/// <summary>Materializes a primitive value. No op or non-primitive values.</summary> /// <param name="type">Type of value to set.</param> /// <param name="wireTypeName">Type name from the payload.</param> /// <param name="value">Value of primitive provided by ODL.</param> /// <param name="throwOnNullMessage">The exception message if the value is null.</param> /// <param name="materializedValue">The materialized value.</param> /// <returns>true if the value was set; false if it wasn't (typically because it's a complex value).</returns> private bool MaterializePrimitiveDataValue(Type type, string wireTypeName, object value, Func <string> throwOnNullMessage, out object materializedValue) { Debug.Assert(type != null, "type != null"); ClientTypeAnnotation nestedElementType = null; Type underlyingType = Nullable.GetUnderlyingType(type) ?? type; PrimitiveType ptype; bool knownType = PrimitiveType.TryGetPrimitiveType(underlyingType, out ptype); if (!knownType) { nestedElementType = this.context.ResolveTypeForMaterialization(type, wireTypeName); Debug.Assert(nestedElementType != null, "nestedElementType != null -- otherwise ReadTypeAttribute (or someone!) should throw"); knownType = PrimitiveType.TryGetPrimitiveType(nestedElementType.ElementType, out ptype); } if (knownType) { if (value == null) { if (!ClientTypeUtil.CanAssignNull(type)) { throw new InvalidOperationException(throwOnNullMessage()); } materializedValue = null; } else { materializedValue = this.PrimitivePropertyConverter.ConvertPrimitiveValue(value, underlyingType); } return(true); } else { materializedValue = null; return(false); } }
private IEdmProperty CreateEdmProperty(IEdmStructuredType declaringType, PropertyInfo propertyInfo) { IEdmProperty property; IEdmType edmType = this.GetOrCreateEdmTypeInternal(propertyInfo.PropertyType).EdmType; bool isNullable = ClientTypeUtil.CanAssignNull(propertyInfo.PropertyType); if ((edmType.TypeKind == EdmTypeKind.Entity) || ((edmType.TypeKind == EdmTypeKind.Collection) && (((IEdmCollectionType)edmType).ElementType.TypeKind() == EdmTypeKind.Entity))) { IEdmEntityType type2 = declaringType as IEdmEntityType; if (type2 == null) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.ClientTypeCache_NonEntityTypeCannotContainEntityProperties(propertyInfo.Name, propertyInfo.DeclaringType.ToString())); } property = EdmNavigationProperty.CreateNavigationPropertyWithPartner(propertyInfo.Name, edmType.ToEdmTypeReference(isNullable), null, false, EdmOnDeleteAction.None, "Partner", type2.ToEdmTypeReference(true), null, false, EdmOnDeleteAction.None); } else { property = new EdmStructuralProperty(declaringType, propertyInfo.Name, edmType.ToEdmTypeReference(isNullable)); } property.SetClientPropertyAnnotation(new ClientPropertyAnnotation(property, propertyInfo, this.protocolVersion)); return(property); }
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); }
protected sealed override bool ReadImplementation() { if (this.hasReadValue) { return(false); } try { ClientEdmModel model = ClientEdmModel.GetModel(base.ResponseInfo.MaxProtocolVersion); IEdmTypeReference expectedType = model.GetOrCreateEdmType(base.ExpectedType).ToEdmTypeReference(ClientTypeUtil.CanAssignNull(base.ExpectedType)); if ((this.SingleResult.HasValue && !this.SingleResult.Value) && (expectedType.Definition.TypeKind != EdmTypeKind.Collection)) { expectedType = model.GetOrCreateEdmType(typeof(ICollection <>).MakeGenericType(new Type[] { base.ExpectedType })).ToEdmTypeReference(false); } this.ReadFromMessageReader(this.messageReader, expectedType); } catch (ODataErrorException exception) { throw new DataServiceClientException(System.Data.Services.Client.Strings.Deserialize_ServerException(exception.Error.Message), exception); } catch (ODataException exception2) { throw new InvalidOperationException(exception2.Message, exception2); } catch (ArgumentException exception3) { throw new InvalidOperationException(exception3.Message, exception3); } finally { this.hasReadValue = true; } return(true); }
/// <summary> /// Creates an Edm property. /// </summary> /// <param name="declaringType">Type declaring this property.</param> /// <param name="propertyInfo">PropertyInfo instance for this property.</param> /// <returns>Returns a new instance of Edm property.</returns> private IEdmProperty CreateEdmProperty(IEdmStructuredType declaringType, PropertyInfo propertyInfo) { IEdmType propertyEdmType = this.GetOrCreateEdmTypeInternal(propertyInfo.PropertyType).EdmType; Debug.Assert( propertyEdmType.TypeKind == EdmTypeKind.Entity || propertyEdmType.TypeKind == EdmTypeKind.Complex || propertyEdmType.TypeKind == EdmTypeKind.Primitive || propertyEdmType.TypeKind == EdmTypeKind.Collection, "Property kind should be Entity, Complex, Primitive or Collection."); IEdmProperty edmProperty; bool isPropertyNullable = ClientTypeUtil.CanAssignNull(propertyInfo.PropertyType); if (propertyEdmType.TypeKind == EdmTypeKind.Entity || (propertyEdmType.TypeKind == EdmTypeKind.Collection && ((IEdmCollectionType)propertyEdmType).ElementType.TypeKind() == EdmTypeKind.Entity)) { IEdmEntityType declaringEntityType = declaringType as IEdmEntityType; if (declaringEntityType == null) { throw c.Error.InvalidOperation(c.Strings.ClientTypeCache_NonEntityTypeCannotContainEntityProperties(propertyInfo.Name, propertyInfo.DeclaringType.ToString())); } // Create a navigation property representing one side of an association. // The partner representing the other side exists only inside this property and is not added to the target entity type, // so it should not cause any name collisions. edmProperty = EdmNavigationProperty.CreateNavigationPropertyWithPartner( propertyInfo.Name, propertyEdmType.ToEdmTypeReference(isPropertyNullable), /*dependentProperties*/ null, /*containsTarget*/ false, EdmOnDeleteAction.None, "Partner", declaringEntityType.ToEdmTypeReference(true), /*partnerDependentProperties*/ null, /*partnerContainsTarget*/ false, EdmOnDeleteAction.None); } else { edmProperty = new EdmStructuralProperty(declaringType, propertyInfo.Name, propertyEdmType.ToEdmTypeReference(isPropertyNullable)); } FieldInfo backingField = null; if (this.ResolveBackingField != null) { // We only do this for "collections of entities" OR "complex properties" if (propertyEdmType.TypeKind == EdmTypeKind.Collection && !propertyEdmType.IsPrimitive() || propertyEdmType.TypeKind == EdmTypeKind.Complex) { backingField = this.ResolveBackingField(propertyInfo); } if (backingField != null && backingField.FieldType != propertyInfo.PropertyType) { backingField = null; // We disregard returned FieldInfo that has the wrong type. } } edmProperty.SetClientPropertyAnnotation(new ClientPropertyAnnotation(edmProperty, propertyInfo, backingField, this)); return(edmProperty); }
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); }
internal static object ProjectionValueForPath(ODataEntityMaterializer materializer, MaterializerEntry entry, Type expectedType, ProjectionPath path) { if ((path.Count == 0) || ((path.Count == 1) && (path[0].Member == null))) { if (!entry.EntityHasBeenResolved) { materializer.Materialize(entry, expectedType, false); } return(entry.ResolvedObject); } object streamLink = null; ODataNavigationLink link = null; ODataProperty atomProperty = null; ICollection <ODataNavigationLink> navigationLinks = entry.NavigationLinks; IEnumerable <ODataProperty> properties = entry.Entry.Properties; ClientEdmModel model = ClientEdmModel.GetModel(materializer.ResponseInfo.MaxProtocolVersion); for (int i = 0; i < path.Count; i++) { Func <StreamDescriptor, bool> predicate = null; Func <ODataNavigationLink, bool> func2 = null; Func <ODataProperty, bool> func3 = null; Func <ODataProperty, bool> func4 = null; Func <ODataNavigationLink, bool> func5 = null; string propertyName; ProjectionPathSegment segment = path[i]; if (segment.Member != null) { bool flag = i == (path.Count - 1); propertyName = segment.Member; expectedType = segment.SourceTypeAs ?? expectedType; ClientPropertyAnnotation property = model.GetClientTypeAnnotation(model.GetOrCreateEdmType(expectedType)).GetProperty(propertyName, false); if (property.IsStreamLinkProperty) { if (predicate == null) { predicate = sd => sd.Name == propertyName; } StreamDescriptor descriptor = entry.EntityDescriptor.StreamDescriptors.Where <StreamDescriptor>(predicate).SingleOrDefault <StreamDescriptor>(); if (descriptor == null) { if (segment.SourceTypeAs == null) { throw new InvalidOperationException(System.Data.Services.Client.Strings.AtomMaterializer_PropertyMissing(propertyName, entry.Entry.Id)); } return(WebUtil.GetDefaultValue <DataServiceStreamLink>()); } streamLink = descriptor.StreamLink; } else { if (segment.SourceTypeAs != null) { if (func2 == null) { func2 = p => p.Name == propertyName; } if (!navigationLinks.Any <ODataNavigationLink>(func2)) { if (func3 == null) { func3 = p => p.Name == propertyName; } if (!properties.Any <ODataProperty>(func3) && flag) { return(WebUtil.GetDefaultValue(property.PropertyType)); } } } if (func4 == null) { func4 = p => p.Name == propertyName; } atomProperty = properties.Where <ODataProperty>(func4).FirstOrDefault <ODataProperty>(); if (func5 == null) { func5 = p => p.Name == propertyName; } link = ((atomProperty == null) && (navigationLinks != null)) ? navigationLinks.Where <ODataNavigationLink>(func5).FirstOrDefault <ODataNavigationLink>() : null; if ((link == null) && (atomProperty == null)) { throw new InvalidOperationException(System.Data.Services.Client.Strings.AtomMaterializer_PropertyMissing(propertyName, entry.Entry.Id)); } if (link != null) { ValidatePropertyMatch(property, link); MaterializerNavigationLink link2 = MaterializerNavigationLink.GetLink(link); if (link2.Feed != null) { MaterializerFeed feed = MaterializerFeed.GetFeed(link2.Feed); Type implementationType = ClientTypeUtil.GetImplementationType(segment.ProjectionType, typeof(ICollection <>)); if (implementationType == null) { implementationType = ClientTypeUtil.GetImplementationType(segment.ProjectionType, typeof(IEnumerable <>)); } Type nestedExpectedType = implementationType.GetGenericArguments()[0]; Type projectionType = segment.ProjectionType; if (projectionType.IsInterfaceEx() || ODataMaterializer.IsDataServiceCollection(projectionType)) { projectionType = typeof(Collection <>).MakeGenericType(new Type[] { nestedExpectedType }); } IEnumerable list = (IEnumerable)Util.ActivatorCreateInstance(projectionType, new object[0]); MaterializeToList(materializer, list, nestedExpectedType, feed.Entries); if (ODataMaterializer.IsDataServiceCollection(segment.ProjectionType)) { list = (IEnumerable)Util.ActivatorCreateInstance(WebUtil.GetDataServiceCollectionOfT(new Type[] { nestedExpectedType }), new object[] { list, TrackingMode.None }); } ProjectionPlan plan = CreatePlanForShallowMaterialization(nestedExpectedType); materializer.FoundNextLinkForCollection(list, feed.Feed.NextPageLink, plan); streamLink = list; } else if (link2.Entry != null) { MaterializerEntry entry2 = link2.Entry; if (flag) { if ((entry2.Entry != null) && !entry2.EntityHasBeenResolved) { materializer.Materialize(entry2, property.PropertyType, false); } } else { CheckEntryToAccessNotNull(entry2, propertyName); } properties = entry2.Properties; navigationLinks = entry2.NavigationLinks; streamLink = entry2.ResolvedObject; entry = entry2; } } else { if (atomProperty.Value is ODataStreamReferenceValue) { streamLink = null; navigationLinks = ODataMaterializer.EmptyLinks; properties = ODataMaterializer.EmptyProperties; continue; } ValidatePropertyMatch(property, atomProperty); if (ClientTypeUtil.TypeOrElementTypeIsEntity(property.PropertyType)) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.AtomMaterializer_InvalidEntityType(property.EntityCollectionItemType ?? property.PropertyType)); } if (property.IsPrimitiveOrComplexCollection) { object instance = streamLink ?? (entry.ResolvedObject ?? Util.ActivatorCreateInstance(expectedType, new object[0])); ODataMaterializer.ApplyDataValue(model.GetClientTypeAnnotation(model.GetOrCreateEdmType(instance.GetType())), atomProperty, materializer.ResponseInfo.IgnoreMissingProperties, materializer.ResponseInfo, instance); navigationLinks = ODataMaterializer.EmptyLinks; properties = ODataMaterializer.EmptyProperties; } else if (atomProperty.Value is ODataComplexValue) { ODataComplexValue complexValue = atomProperty.Value as ODataComplexValue; ODataMaterializer.MaterializeComplexTypeProperty(property.PropertyType, complexValue, materializer.ResponseInfo.IgnoreMissingProperties, materializer.ResponseInfo); properties = complexValue.Properties; navigationLinks = ODataMaterializer.EmptyLinks; } else { if ((atomProperty.Value == null) && !ClientTypeUtil.CanAssignNull(property.NullablePropertyType)) { throw new InvalidOperationException(System.Data.Services.Client.Strings.AtomMaterializer_CannotAssignNull(atomProperty.Name, property.NullablePropertyType)); } ODataMaterializer.MaterializePrimitiveDataValue(property.NullablePropertyType, atomProperty); navigationLinks = ODataMaterializer.EmptyLinks; properties = ODataMaterializer.EmptyProperties; } streamLink = atomProperty.GetMaterializedValue(); } } expectedType = property.PropertyType; } } return(streamLink); }
/// <summary> /// Gets the CLR type based on the <see cref="IEdmTypeReference"/> and the current data service context. /// </summary> /// <param name="context">The data service context.</param> /// <param name="edmTypeReference">The specified edm type reference.</param> /// <param name="isBindingParameter">This flag indicates whether the edm type reference is used for a binding parameter.</param> /// <param name="clrType">The output parameter to return the CLR type.</param> /// <returns>True if the CLR type is found, or false.</returns> private static bool TryGetClrTypeFromEdmTypeReference(DataServiceContext context, IEdmTypeReference edmTypeReference, bool isBindingParameter, out Type clrType) { EdmTypeKind typeKind = edmTypeReference.Definition.TypeKind; if (typeKind == EdmTypeKind.None) { clrType = null; return(false); } if (typeKind == EdmTypeKind.Primitive) { PrimitiveType primitiveType = null; if (PrimitiveType.TryGetPrimitiveType(edmTypeReference.Definition.FullName(), out primitiveType)) { clrType = primitiveType.ClrType; if (edmTypeReference.IsNullable && ClientTypeUtil.CanAssignNull(clrType)) { clrType = typeof(Nullable <>).MakeGenericType(clrType); } return(true); } } if (typeKind == EdmTypeKind.Collection) { Type elementType; if (TryGetClrTypeFromEdmTypeReference(context, ((IEdmCollectionTypeReference)edmTypeReference).ElementType(), false, out elementType)) { if (isBindingParameter) { clrType = typeof(DataServiceQuery <>).MakeGenericType(elementType); } else { clrType = typeof(List <>).MakeGenericType(elementType); } return(true); } } if (typeKind == EdmTypeKind.Complex || typeKind == EdmTypeKind.Entity || typeKind == EdmTypeKind.Enum) { clrType = ResolveTypeFromName(context, edmTypeReference.FullName()); if (clrType == null) { return(false); } if (isBindingParameter) { clrType = typeof(DataServiceQuerySingle <>).MakeGenericType(clrType); } return(true); } clrType = null; return(false); }
/// <summary> /// Implementation of Read>. /// </summary> /// <returns> /// Return value of Read/> /// </returns> protected sealed override bool ReadImplementation() { if (!this.hasReadValue) { try { ClientEdmModel model = this.MaterializerContext.Model; Type expectedType = this.ExpectedType; IEdmTypeReference expectedClientType = model.GetOrCreateEdmType(expectedType).ToEdmTypeReference(ClientTypeUtil.CanAssignNull(expectedType)); if ((this.SingleResult.HasValue && !this.SingleResult.Value) && expectedClientType.Definition.TypeKind != EdmTypeKind.Collection) { expectedType = typeof(ICollection <>).MakeGenericType(expectedType); // we do not allow null values for collection expectedClientType = model.GetOrCreateEdmType(expectedType).ToEdmTypeReference(false); } IEdmTypeReference expectedReaderType = this.MaterializerContext.ResolveExpectedTypeForReading(expectedType).ToEdmTypeReference(expectedClientType.IsNullable); this.ReadWithExpectedType(expectedClientType, expectedReaderType); } catch (ODataErrorException e) { throw new DataServiceClientException(ClientStrings.Deserialize_ServerException(e.Error.Message), e); } catch (ODataException e) { throw new InvalidOperationException(e.Message, e); } catch (ArgumentException e) { throw new InvalidOperationException(e.Message, e); } finally { this.hasReadValue = true; } return(true); } else { return(false); } }