internal MaterializeAtom(ResponseInfo responseInfo, QueryComponents queryComponents, ProjectionPlan plan, IODataResponseMessage responseMessage, ODataPayloadKind payloadKind) { Type type; this.responseInfo = responseInfo; this.elementType = queryComponents.LastSegmentType; this.MergeOptionValue = responseInfo.MergeOption; this.expectingPrimitiveValue = PrimitiveType.IsKnownNullableType(this.elementType); Type materializerType = GetTypeForMaterializer(this.expectingPrimitiveValue, this.elementType, responseInfo.MaxProtocolVersion, out type); this.materializer = ODataMaterializer.CreateMaterializerForMessage(responseMessage, responseInfo, materializerType, queryComponents, plan, payloadKind); }
internal MaterializeAtom(ResponseInfo responseInfo, IEnumerable <ODataEntry> entries, Type elementType) { Type type; this.responseInfo = responseInfo; this.elementType = elementType; this.MergeOptionValue = responseInfo.MergeOption; this.expectingPrimitiveValue = PrimitiveType.IsKnownNullableType(elementType); Type expectedType = GetTypeForMaterializer(this.expectingPrimitiveValue, this.elementType, responseInfo.MaxProtocolVersion, out type); QueryComponents queryComponents = new QueryComponents(null, Util.DataServiceVersionEmpty, elementType, null, null); this.materializer = new ODataEntriesEntityMaterializer(entries, responseInfo, queryComponents, expectedType, null); }
/// <summary> /// Returns the primitive property value. /// </summary> /// <param name="propertyValue">Value of the property.</param> /// <param name="propertyType">Type of the property.</param> /// <returns>Returns the value of the primitive property.</returns> private static object ConvertPrimitiveValueToRecognizedODataType(object propertyValue, Type propertyType) { Debug.Assert(PrimitiveType.IsKnownNullableType(propertyType), "GetPrimitiveValue must be called only for primitive types"); Debug.Assert(propertyValue == null || PrimitiveType.IsKnownType(propertyValue.GetType()), "GetPrimitiveValue method must be called for primitive values only"); if (propertyValue == null) { return(null); } PrimitiveType primitiveType; PrimitiveType.TryGetPrimitiveType(propertyType, out primitiveType); Debug.Assert(primitiveType != null, "must be a known primitive type"); // Do the conversion for types that are not supported by ODataLib e.g. char[], char, etc if (propertyType == typeof(Char) || propertyType == typeof(Char[]) || propertyType == typeof(Type) || propertyType == typeof(Uri) || propertyType == typeof(Xml.Linq.XDocument) || propertyType == typeof(Xml.Linq.XElement)) { return(primitiveType.TypeConverter.ToString(propertyValue)); } #if !ASTORIA_LIGHT && !PORTABLELIB else if (propertyType.FullName == "System.Data.Linq.Binary") { // For System.Data.Linq.Binary, it is a delay loaded type. Hence checking it based on name. // PrimitiveType.IsKnownType checks for binary type based on name and assembly. Hence just // checking name here is sufficient, since any other type with the same name, but in different // assembly will return false for PrimitiveType.IsKnownNullableType. // Since ODataLib does not understand binary type, we need to convert the value to byte[]. return(((BinaryTypeConverter)primitiveType.TypeConverter).ToArray(propertyValue)); } #endif else if (primitiveType.EdmTypeName == null) { // case StorageType.DateTimeOffset: // case StorageType.TimeSpan: // case StorageType.UInt16: // case StorageType.UInt32: // case StorageType.UInt64: // don't support reverse mappings for these types in this version // allows us to add real server support in the future without a // "breaking change" in the future client throw new NotSupportedException(Strings.ALinq_CantCastToUnsupportedPrimitive(propertyType.Name)); } return(propertyValue); }
/// <summary> /// constructor /// </summary> /// <param name="responseInfo">originating context</param> /// <param name="entries">entries that needs to be materialized.</param> /// <param name="elementType">result type.</param> /// <param name="format">The format of the response being materialized from.</param> internal MaterializeAtom(ResponseInfo responseInfo, IEnumerable <ODataEntry> entries, Type elementType, ODataFormat format) { this.responseInfo = responseInfo; this.elementType = elementType; this.expectingPrimitiveValue = PrimitiveType.IsKnownNullableType(elementType); Type implementationType; Type materializerType = GetTypeForMaterializer(this.expectingPrimitiveValue, this.elementType, responseInfo.Model, out implementationType); QueryComponents qc = new QueryComponents(null, Util.DataServiceVersionEmpty, elementType, null, null); ODataMaterializerContext context = new ODataMaterializerContext(responseInfo); EntityTrackingAdapter entityTrackingAdapter = new EntityTrackingAdapter(responseInfo.EntityTracker, responseInfo.MergeOption, responseInfo.Model, responseInfo.Context); this.materializer = new ODataEntriesEntityMaterializer(entries, context, entityTrackingAdapter, qc, materializerType, null, format); }
internal static void ValidateCollection(Type collectionItemType, object propertyValue, string propertyName) { if (!PrimitiveType.IsKnownNullableType(collectionItemType) && (collectionItemType.GetInterfaces().SingleOrDefault <Type>(t => (t == typeof(IEnumerable))) != null)) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.ClientType_CollectionOfCollectionNotSupported); } if (propertyValue == null) { if (propertyName != null) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.Collection_NullCollectionNotSupported(propertyName)); } throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.Collection_NullNonPropertyCollectionNotSupported(collectionItemType)); } }
internal static bool IsCLRTypeCollection(Type type, DataServiceProtocolVersion maxProtocolVersion) { if (!PrimitiveType.IsKnownNullableType(type)) { Type implementationType = ClientTypeUtil.GetImplementationType(type, typeof(ICollection <>)); if ((implementationType != null) && !ClientTypeUtil.TypeIsEntity(implementationType.GetGenericArguments()[0], maxProtocolVersion)) { if (maxProtocolVersion <= DataServiceProtocolVersion.V2) { throw new InvalidOperationException(System.Data.Services.Client.Strings.WebUtil_CollectionTypeNotSupportedInV2OrBelow(type.FullName)); } return(true); } } return(false); }
internal static void ValidatePrimitiveCollectionItem(object itemValue, string propertyName, Type collectionItemType) { Type type = itemValue.GetType(); if (!PrimitiveType.IsKnownNullableType(type)) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.Collection_ComplexTypesInCollectionOfPrimitiveTypesNotAllowed); } if (!collectionItemType.IsAssignableFrom(type)) { if (propertyName != null) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.WebUtil_TypeMismatchInCollection(propertyName)); } throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.WebUtil_TypeMismatchInNonPropertyCollection(collectionItemType)); } }
/// <summary> /// Visits a member access expression in non-entity projections, validating that /// it's correct and recording the path visit to include in a projection if necessary. /// </summary> /// <param name="m">Expression to visit.</param> /// <returns>The same expression.</returns> /// <remarks> /// The projection analyzer runs after funcletization, so a member expression /// rather than a constant expression implies that this is correlated to /// a parameter, by dotting through the argument in valid cases, and possibly /// more complex cases in others like new DSC(p.Orders)*.Foo* <- .Foo is invalid. /// </remarks> internal override Expression VisitMemberAccess(MemberExpression m) { Debug.Assert(m != null, "m != null"); Type expressionType = m.Expression.Type; this.leafExpressionIsMemberAccess = true; // if primitive or nullable primitive, allow member access... i.e. calling Value on nullable<int> if (PrimitiveType.IsKnownNullableType(expressionType)) { this.leafExpressionIsMemberAccess = false; return(base.VisitMemberAccess(m)); } // Only allowed to project entities, also it is ok to do client side projections on complex types. // Details on the fix for the Dev11 bug 350541 "Inconsistency between Count() method call and Count property projection on clr type collections": // Relax check to only throw if IsCollectionProducingExpression returns true. // This enables client side projections (for example "Count") on Clr type collections, like ReadOnlyCollection (which is used in spatial types), ICollection, IList, etc. // We already allow client side method calls (like Linq extension method "Count()") on clr type collections, so it makes client side projections consistent. // Note: it will still throw for List<T> (because IsCollectionProducingExpression returns true for List<T>), // however this is consistent with how we handle MethodCallExpression on clr type collections // and changing IsCollectionProducingExpression seems risky at this point as it's used in a lot of places. if (IsCollectionProducingExpression(m.Expression)) { throw new NotSupportedException(Strings.ALinq_ExpressionNotSupportedInProjection(this.type, m.ToString())); } PropertyInfo pi; Expression boundTarget; if (ResourceBinder.PatternRules.MatchNonPrivateReadableProperty(m, out pi, out boundTarget)) { Expression e = base.VisitMemberAccess(m); if (ClientTypeUtil.TypeOrElementTypeIsEntity(expressionType)) { Type convertedType; ResourceBinder.StripTo <Expression>(m.Expression, out convertedType); box.AppendPropertyToPath(pi, convertedType, this.context); this.leafExpressionIsMemberAccess = false; } return(e); } throw new NotSupportedException(Strings.ALinq_ExpressionNotSupportedInProjection(this.type, m.ToString())); }
internal override Expression VisitMemberAccess(MemberExpression m) { ExpressionAnnotation annotation; Expression expression = m.Expression; if (PrimitiveType.IsKnownNullableType(expression.Type)) { return(base.VisitMemberAccess(m)); } Expression key = this.Visit(expression); if (this.annotations.TryGetValue(key, out annotation)) { return(this.RebindMemberAccess(m, annotation)); } return(Expression.MakeMemberAccess(key, m.Member)); }
/// <summary> /// Get or create a client EDM type instance. /// </summary> /// <param name="type">type to wrap</param> /// <returns>client type</returns> private EdmTypeCacheValue GetOrCreateEdmTypeInternal(Type type) { Debug.Assert(type != null, "type != null"); EdmTypeCacheValue cachedEdmType; lock (this.clrToEdmTypeCache) { this.clrToEdmTypeCache.TryGetValue(type, out cachedEdmType); } if (cachedEdmType == null) { if (PrimitiveType.IsKnownNullableType(type)) { cachedEdmType = this.GetOrCreateEdmTypeInternal(null /*baseType*/, type, ClientTypeUtil.EmptyPropertyInfoArray, false /*isEntity*/, false /*hasProperties*/); } else { PropertyInfo[] keyProperties; bool hasProperties; Type[] hierarchy = ClientEdmModel.GetTypeHierarchy(type, out keyProperties, out hasProperties); Debug.Assert(keyProperties == null || keyProperties.Length == 0 || keyProperties.All(p => p.DeclaringType == keyProperties[0].DeclaringType), "All key properties must be declared on the same type."); bool isEntity = keyProperties != null; keyProperties = keyProperties ?? ClientTypeUtil.EmptyPropertyInfoArray; foreach (Type t in hierarchy) { // Pass in the full list of key properties for the most base type to be added there. We only allow key properties to be // declared on the same type. IEdmStructuredType edmBaseType = cachedEdmType == null ? null : cachedEdmType.EdmType as IEdmStructuredType; cachedEdmType = this.GetOrCreateEdmTypeInternal(edmBaseType, t, keyProperties, isEntity, t == type ? hasProperties : (bool?)null); // Pass in an empty PropertyInfo array on subsequent derived types. keyProperties = ClientTypeUtil.EmptyPropertyInfoArray; } } } Debug.Assert(cachedEdmType != null, "cachedEdmType != null"); return(cachedEdmType); }
#pragma warning restore 649 #endif #endregion Private fields /// <summary> /// constructor /// </summary> /// <param name="responseInfo">originating context</param> /// <param name="queryComponents">Query components (projection, expected type)</param> /// <param name="plan">Projection plan (if compiled in an earlier query).</param> /// <param name="responseMessage">responseMessage</param> /// <param name="payloadKind">The kind of the payload to materialize.</param> internal MaterializeAtom( ResponseInfo responseInfo, QueryComponents queryComponents, ProjectionPlan plan, IODataResponseMessage responseMessage, ODataPayloadKind payloadKind) { Debug.Assert(queryComponents != null, "queryComponents != null"); this.responseInfo = responseInfo; this.elementType = queryComponents.LastSegmentType; this.expectingPrimitiveValue = PrimitiveType.IsKnownNullableType(elementType); Debug.Assert(responseMessage != null, "Response message is null! Did you mean to use Materializer.ResultsWrapper/EmptyResults?"); this.responseMessage = responseMessage; Type implementationType; Type materializerType = GetTypeForMaterializer(this.expectingPrimitiveValue, this.elementType, responseInfo.Model, out implementationType); this.materializer = ODataMaterializer.CreateMaterializerForMessage(responseMessage, responseInfo, materializerType, queryComponents, plan, payloadKind); }
internal void OnPrimitiveOrComplexCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { object obj2; string str; Type type; Util.CheckArgumentNull <object>(sender, "sender"); Util.CheckArgumentNull <NotifyCollectionChangedEventArgs>(e, "e"); this.bindingGraph.GetPrimitiveOrComplexCollectionInfo(sender, out obj2, out str, out type); if (!PrimitiveType.IsKnownNullableType(type)) { switch (e.Action) { case NotifyCollectionChangedAction.Add: this.OnAddToComplexTypeCollection(sender, e.NewItems); goto Label_00BC; case NotifyCollectionChangedAction.Remove: this.OnRemoveFromComplexTypeCollection(sender, e.OldItems); goto Label_00BC; case NotifyCollectionChangedAction.Replace: this.OnRemoveFromComplexTypeCollection(sender, e.OldItems); this.OnAddToComplexTypeCollection(sender, e.NewItems); goto Label_00BC; case NotifyCollectionChangedAction.Move: goto Label_00BC; case NotifyCollectionChangedAction.Reset: this.bindingGraph.RemoveCollection(sender); goto Label_00BC; } throw new InvalidOperationException(Strings.DataBinding_CollectionChangedUnknownActionCollection(e.Action, sender.GetType())); } Label_00BC: this.HandleUpdateEntity(obj2, str, sender); }
/// <summary> /// Checks if the collection is valid. Throws if the collection is not valid. /// </summary> /// <param name="collectionItemType">The type of the collection item. Can not be null.</param> /// <param name="propertyValue">Collection instance to be validated.</param> /// <param name="propertyName">The name of the property being serialized (for exception messages). Can be null if the type is not a property.</param> internal static void ValidateCollection(Type collectionItemType, object propertyValue, string propertyName) { Debug.Assert(collectionItemType != null, "collectionItemType != null"); // nested collections are not supported. Need to exclude primitve types - e.g. string implements IEnumerable<char> if (!PrimitiveType.IsKnownNullableType(collectionItemType) && collectionItemType.GetInterfaces().SingleOrDefault(t => t == typeof(IEnumerable)) != null) { throw Error.InvalidOperation(Strings.ClientType_CollectionOfCollectionNotSupported); } if (propertyValue == null) { if (propertyName != null) { throw Error.InvalidOperation(Strings.Collection_NullCollectionNotSupported(propertyName)); } else { throw Error.InvalidOperation(Strings.Collection_NullNonPropertyCollectionNotSupported(collectionItemType)); } } }
/// <summary> /// Checks if the provided type is a collection type (i.e. it implements ICollection and the collection item type is not an entity). /// </summary> /// <param name="type">Type being checked.</param> /// <param name="model">The client model.</param> /// <returns>True if the CLR type is a collection compatible type. False otherwise.</returns> internal static bool IsCLRTypeCollection(Type type, ClientEdmModel model) { // char[] and byte[] implements ICollection<> but we should not threat them as collections since they are primitive types for us. if (!PrimitiveType.IsKnownNullableType(type)) { Type collectionType = ClientTypeUtil.GetImplementationType(type, typeof(ICollection <>)); if (collectionType != null) { // collectionType is ICollection so we know that the first generic parameter // is the collection item type if (!ClientTypeUtil.TypeIsEntity(collectionType.GetGenericArguments()[0], model)) { if (model.MaxProtocolVersion <= DataServiceProtocolVersion.V2) { throw new InvalidOperationException(Strings.WebUtil_CollectionTypeNotSupportedInV2OrBelow(type.FullName)); } return(true); } } } return(false); }
internal override Expression VisitUnary(UnaryExpression u) { UnaryExpression expression = (UnaryExpression)base.VisitUnary(u); Expression rewritten = expression; this.RecordRewrite(u, rewritten); if ((expression.NodeType != ExpressionType.Convert) && (expression.NodeType != ExpressionType.TypeAs)) { return(rewritten); } if (!expression.Type.IsAssignableFrom(expression.Operand.Type)) { return(rewritten); } if ((PrimitiveType.IsKnownNullableType(expression.Operand.Type) || PrimitiveType.IsKnownNullableType(expression.Type)) && !(expression.Operand.Type == expression.Type)) { return(rewritten); } if (ClientTypeUtil.TypeOrElementTypeIsEntity(expression.Operand.Type) && ProjectionAnalyzer.IsCollectionProducingExpression(expression.Operand)) { return(rewritten); } return(expression.Operand); }
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); }