private bool TryProcessDeltaNestedResource(IEdmProperty nestedProperty, object resource, ODataResourceWrapper resourceWrapper, ODataDeserializerContext readContext) { string nestedPropertyName = EdmLibHelpers.GetClrPropertyName(nestedProperty, readContext.Model); IDelta resourceDelta = resource as IDelta; if (resourceDelta == null) { return(false); } if (resourceWrapper == null) { return(resourceDelta.TrySetPropertyReferencedValue(nestedPropertyName, null)); } if (resourceWrapper.Resource.Properties == null) { return(false); } IEdmStructuredTypeReference structuredType = nestedProperty.Type.AsStructured(); Delta propertyValueDelta = CreateDeltaInstance(readContext, resourceWrapper, structuredType); ApplyResourceProperties(propertyValueDelta, resourceWrapper, structuredType, readContext); return(resourceDelta.TrySetPropertyReferencedValue(nestedPropertyName, propertyValueDelta)); }
private Expression CreatePropertyAccessExpression(Expression source, IEdmProperty property, string propertyPath = null) { string propertyName = EdmLibHelpers.GetClrPropertyName(property, this.Model); propertyPath = propertyPath ?? propertyName; if (this.QuerySettings.HandleNullPropagation == HandleNullPropagationOption.True && IsNullable(source.Type) && source != this._lambdaParameter) { Expression cleanSource = this.RemoveInnerNullPropagation(source); Expression propertyAccessExpression = null; propertyAccessExpression = this.GetFlattenedPropertyExpression(propertyPath) ?? Expression.Property(cleanSource, propertyName); // source.property => source == null ? null : [CastToNullable]RemoveInnerNullPropagation(source).property // Notice that we are checking if source is null already. so we can safely remove any null checks when doing source.Property Expression ifFalse = ToNullable(this.ConvertNonStandardPrimitives(propertyAccessExpression)); return (Expression.Condition( test: Expression.Equal(source, NullConstant), ifTrue: Expression.Constant(null, ifFalse.Type), ifFalse: ifFalse)); } else { return(this.GetFlattenedPropertyExpression(propertyPath) ?? this.ConvertNonStandardPrimitives(Expression.Property(source, propertyName))); } }
/// <summary> /// Generates a string to be used as the skip token value within the next link. /// </summary> /// <param name="lastMember"> Object based on which SkipToken value will be generated.</param> /// <param name="model">The edm model.</param> /// <param name="orderByNodes">List of orderByNodes used to generate the skiptoken value.</param> /// <returns>Value for the skiptoken to be used in the next link.</returns> private static string GenerateSkipTokenValue(Object lastMember, IEdmModel model, IList <OrderByNode> orderByNodes) { if (lastMember == null) { return(String.Empty); } IEnumerable <IEdmProperty> propertiesForSkipToken = GetPropertiesForSkipToken(lastMember, model, orderByNodes); StringBuilder skipTokenBuilder = new StringBuilder(String.Empty); if (propertiesForSkipToken == null) { return(skipTokenBuilder.ToString()); } int count = 0; string uriLiteral; object value; int lastIndex = propertiesForSkipToken.Count() - 1; IEdmStructuredObject obj = lastMember as IEdmStructuredObject; foreach (IEdmProperty edmProperty in propertiesForSkipToken) { bool islast = count == lastIndex; string clrPropertyName = EdmLibHelpers.GetClrPropertyName(edmProperty, model); if (obj != null) { obj.TryGetPropertyValue(clrPropertyName, out value); } else { value = lastMember.GetType().GetProperty(clrPropertyName).GetValue(lastMember); } if (value == null) { uriLiteral = ODataUriUtils.ConvertToUriLiteral(value, ODataVersion.V401); } else if (edmProperty.Type.IsEnum()) { ODataEnumValue enumValue = new ODataEnumValue(value.ToString(), value.GetType().FullName); uriLiteral = ODataUriUtils.ConvertToUriLiteral(enumValue, ODataVersion.V401, model); } else if (edmProperty.Type.IsDateTimeOffset() && value is DateTime) { var dateTime = (DateTime)value; var dateTimeOffsetValue = TimeZoneInfoHelper.ConvertToDateTimeOffset(dateTime); uriLiteral = ODataUriUtils.ConvertToUriLiteral(dateTimeOffsetValue, ODataVersion.V401, model); } else { uriLiteral = ODataUriUtils.ConvertToUriLiteral(value, ODataVersion.V401, model); } skipTokenBuilder.Append(edmProperty.Name).Append(propertyDelimiter).Append(uriLiteral).Append(islast ? String.Empty : CommaDelimiter.ToString()); count++; } return(skipTokenBuilder.ToString()); }
internal static void ApplyProperty(ODataProperty property, IEdmStructuredTypeReference resourceType, object resource, ODataDeserializerProvider deserializerProvider, ODataDeserializerContext readContext) { IEdmProperty edmProperty = resourceType.FindProperty(property.Name); bool isDynamicProperty = false; string propertyName = property.Name; if (edmProperty != null) { propertyName = EdmLibHelpers.GetClrPropertyName(edmProperty, readContext.Model); } else { IEdmStructuredType structuredType = resourceType.StructuredDefinition(); isDynamicProperty = structuredType != null && structuredType.IsOpen; } // dynamic properties have null values IEdmTypeReference propertyType = edmProperty != null ? edmProperty.Type : null; EdmTypeKind propertyKind; object value = ConvertValue(property.Value, ref propertyType, deserializerProvider, readContext, out propertyKind); if (isDynamicProperty) { SetDynamicProperty(resource, resourceType, propertyKind, propertyName, value, propertyType, readContext); } else { SetDeclaredProperty(resource, propertyKind, propertyName, value, edmProperty, readContext); } }
private void ApplyResourceSetInNestedProperty(IEdmProperty nestedProperty, object resource, ODataResourceSetWrapper resourceSetWrapper, ODataDeserializerContext readContext) { Contract.Assert(nestedProperty != null); Contract.Assert(resource != null); Contract.Assert(readContext != null); if (readContext.IsDeltaOfT) { IEdmNavigationProperty navigationProperty = nestedProperty as IEdmNavigationProperty; if (navigationProperty != null) { if (TryProcessDeltaNestedResourceSet(nestedProperty, resource, resourceSetWrapper, readContext)) { return; } string message = Error.Format(SRResources.CannotPatchNavigationProperties, navigationProperty.Name, navigationProperty.DeclaringEntityType().FullName()); throw new ODataException(message); } } object value = ReadNestedResourceSetInline(resourceSetWrapper, nestedProperty.Type, readContext); string propertyName = EdmLibHelpers.GetClrPropertyName(nestedProperty, readContext.Model); DeserializationHelpers.SetCollectionProperty(resource, nestedProperty, value, propertyName); }
private void ApplyResourceInNestedProperty(IEdmProperty nestedProperty, object resource, ODataResourceWrapper resourceWrapper, ODataDeserializerContext readContext) { Contract.Assert(nestedProperty != null); Contract.Assert(resource != null); Contract.Assert(readContext != null); if (readContext.IsDeltaOfT) { IEdmNavigationProperty navigationProperty = nestedProperty as IEdmNavigationProperty; if (navigationProperty != null) { string message = Error.Format(SRResources.CannotPatchNavigationProperties, navigationProperty.Name, navigationProperty.DeclaringEntityType().FullName()); throw new ODataException(message); } } object value = ReadNestedResourceInline(resourceWrapper, nestedProperty.Type, readContext); // First resolve Data member alias or annotation, then set the regular // or delta resource accordingly. string propertyName = EdmLibHelpers.GetClrPropertyName(nestedProperty, readContext.Model); DeserializationHelpers.SetProperty(resource, propertyName, value); }
public static IQueryable OrderByProperty(IQueryable query, IEdmModel model, IEdmProperty property, OrderByDirection direction, Type type, bool alreadyOrdered = false) { // property aliasing string propertyName = EdmLibHelpers.GetClrPropertyName(property, model); LambdaExpression orderByLambda = GetPropertyAccessLambda(type, propertyName); return(OrderBy(query, orderByLambda, direction, type, alreadyOrdered)); }
/// <summary> /// Returns all updatable properties for given structured type. /// </summary> /// <param name="model">Edm model.</param> /// <param name="structuredType">The type of the resource.</param> /// <returns></returns> protected static IEnumerable <string> GetUpdatableProperties(IEdmModel model, IEdmStructuredTypeReference structuredType) { // we consider navigation properties to be editable so that @odata.id works for nested resources IEnumerable <string> updatableProperties = structuredType.StructuralProperties() .Cast <IEdmProperty>() .Union(structuredType.NavigationProperties()) .Select(edmProperty => EdmLibHelpers.GetClrPropertyName(edmProperty, model)); return(updatableProperties); }
internal static void ApplyProperty(ODataProperty property, IEdmStructuredTypeReference resourceType, object resource, ODataDeserializerProvider deserializerProvider, ODataDeserializerContext readContext) { IEdmProperty edmProperty = resourceType.FindProperty(property.Name); // try to deserializer the dynamic properties for open type. if (edmProperty == null) { // the logic here works for open complex type and open entity type. IEdmStructuredType structuredType = resourceType.StructuredDefinition(); if (structuredType != null && structuredType.IsOpen) { if (ApplyDynamicProperty(property, structuredType, resource, deserializerProvider, readContext)) { return; } } } string propertyName = property.Name; if (edmProperty != null) { propertyName = EdmLibHelpers.GetClrPropertyName(edmProperty, readContext.Model); } IEdmTypeReference propertyType = edmProperty != null ? edmProperty.Type : null; // open properties have null values EdmTypeKind propertyKind; object value = ConvertValue(property.Value, ref propertyType, deserializerProvider, readContext, out propertyKind); if (propertyKind == EdmTypeKind.Collection) { SetCollectionProperty(resource, edmProperty, value, propertyName); } else { if (!readContext.IsUntyped) { if (propertyKind == EdmTypeKind.Primitive) { value = EdmPrimitiveHelpers.ConvertPrimitiveValue(value, GetPropertyType(resource, propertyName)); } else if (propertyKind == EdmTypeKind.Enum) { value = EnumDeserializationHelpers.ConvertEnumValue(value, GetPropertyType(resource, propertyName)); } } SetProperty(resource, propertyName, value); } }
private object BuildResourceInstance() { if (EdmObject == null) { return(null); } TypedEdmStructuredObject edmStructruredObject = EdmObject as TypedEdmStructuredObject; if (edmStructruredObject != null) { return(edmStructruredObject.Instance); } SelectExpandWrapper selectExpandWrapper = EdmObject as SelectExpandWrapper; if (selectExpandWrapper != null && selectExpandWrapper.UntypedInstance != null) { return(selectExpandWrapper.UntypedInstance); } Type clrType = EdmLibHelpers.GetClrType(StructuredType, EdmModel); if (clrType == null) { throw new InvalidOperationException(Error.Format(SRResources.MappingDoesNotContainResourceType, StructuredType.FullTypeName())); } object resource = Activator.CreateInstance(clrType); foreach (IEdmStructuralProperty property in StructuredType.StructuralProperties()) { object value; if (EdmObject.TryGetPropertyValue(property.Name, out value) && value != null) { string propertyName = EdmLibHelpers.GetClrPropertyName(property, EdmModel); if (value.GetType().IsCollection()) { DeserializationHelpers.SetCollectionProperty(resource, property, value, propertyName); } else { DeserializationHelpers.SetProperty(resource, propertyName, value); } } } return(resource); }
internal static Func <object, object> GetOrCreatePropertyGetter( Type type, string propertyName, IEdmStructuredTypeReference edmType, IEdmModel model, ref ConcurrentDictionary <string, Func <object, object> > propertyGetterCache) { EnsurePropertyGettingCachePopulated(type, edmType, model, ref propertyGetterCache); return(propertyGetterCache.GetOrAdd(propertyName, name => { IEdmProperty property = edmType.FindProperty(name); if (property != null && model != null) { name = EdmLibHelpers.GetClrPropertyName(property, model) ?? name; } return CreatePropertyGetter(type, name); })); }
internal Expression CreatePropertyValueExpression(IEdmEntityType elementType, IEdmProperty property, Expression source) { Contract.Assert(elementType != null); Contract.Assert(property != null); Contract.Assert(source != null); IEdmEntityType declaringType = property.DeclaringType as IEdmEntityType; Contract.Assert(declaringType != null, "only entity types are projected."); // derived property using cast if (elementType != declaringType) { Type castType = EdmLibHelpers.GetClrType(declaringType, _model); if (castType == null) { throw new ODataException(Error.Format(SRResources.MappingDoesNotContainEntityType, declaringType.FullName())); } source = Expression.TypeAs(source, castType); } string propertyName = EdmLibHelpers.GetClrPropertyName(property, _model); Expression propertyValue = Expression.Property(source, propertyName); if (_settings.HandleNullPropagation == HandleNullPropagationOption.True) { // source == null ? null : propertyValue propertyValue = Expression.Condition( test: Expression.Equal(source, Expression.Constant(null)), ifTrue: Expression.Constant(null, propertyValue.Type.ToNullable()), ifFalse: ExpressionHelpers.ToNullable(propertyValue)); } else { // need to cast this to nullable as EF would fail while materializing if the property is not nullable and source is null. propertyValue = ExpressionHelpers.ToNullable(propertyValue); } return(propertyValue); }
private bool TryProcessDeltaNestedResourceSet(IEdmProperty collectionProperty, object resource, ODataResourceSetWrapper resourceSetWrapper, ODataDeserializerContext readContext) { string collectionPropertyName = EdmLibHelpers.GetClrPropertyName(collectionProperty, readContext.Model); IDelta resourceDelta = resource as IDelta; if (resourceDelta == null) { return(false); } if (resourceSetWrapper == null) { return(resourceDelta.TrySetPropertyReferencedValue(collectionPropertyName, null)); } if (resourceSetWrapper.Resources == null) { return(false); } IEdmStructuredTypeReference structuredElementType = collectionProperty.Type.AsCollection().ElementType().AsStructured(); Type clrElementType = EdmLibHelpers.GetClrType(structuredElementType, readContext.Model); Type deltaType = typeof(Delta <>).MakeGenericType(clrElementType); IEnumerable <string> structuralProperties = GetUpdatableProperties(readContext.Model, structuredElementType); IList elementDeltas = new ArrayList(); foreach (ODataResourceWrapper resourceWrapper in resourceSetWrapper.Resources) { Delta elementDelta = (Delta)Activator.CreateInstance(deltaType, clrElementType, structuralProperties); ApplyResourceProperties(elementDelta, resourceWrapper, structuredElementType, readContext); elementDeltas.Add(elementDelta); } return(resourceDelta.TrySetPropertyCollectionValue(collectionPropertyName, elementDeltas)); }
private void ApplyFeedInNavigationProperty(IEdmNavigationProperty navigationProperty, object entityResource, ODataFeedWithEntries feed, ODataDeserializerContext readContext) { Contract.Assert(navigationProperty != null && navigationProperty.PropertyKind == EdmPropertyKind.Navigation, "navigationProperty != null && navigationProperty.TypeKind == ResourceTypeKind.EntityType"); Contract.Assert(entityResource != null, "entityResource != null"); if (readContext.IsDeltaOfT) { string message = Error.Format(SRResources.CannotPatchNavigationProperties, navigationProperty.Name, navigationProperty.DeclaringEntityType().FullName()); throw new ODataException(message); } ODataEdmTypeDeserializer deserializer = DeserializerProvider.GetEdmTypeDeserializer(navigationProperty.Type); if (deserializer == null) { throw new SerializationException(Error.Format(SRResources.TypeCannotBeDeserialized, navigationProperty.Type.FullName(), typeof(ODataMediaTypeFormatter))); } object value = deserializer.ReadInline(feed, navigationProperty.Type, readContext); string propertyName = EdmLibHelpers.GetClrPropertyName(navigationProperty, readContext.Model); DeserializationHelpers.SetCollectionProperty(entityResource, navigationProperty, value, propertyName, readContext.TimeZoneInfo); }
internal static Func <object, object> GetOrCreatePropertyGetter( Type type, string propertyName, IEdmStructuredTypeReference edmType, IEdmModel model) { Tuple <string, Type> key = Tuple.Create(propertyName, type); Func <object, object> getter; if (!_propertyGetterCache.TryGetValue(key, out getter)) { IEdmProperty property = edmType.FindProperty(propertyName); if (property != null && model != null) { propertyName = EdmLibHelpers.GetClrPropertyName(property, model) ?? propertyName; } getter = CreatePropertyGetter(type, propertyName); _propertyGetterCache[key] = getter; } return(getter); }
internal static void ApplyProperty(ODataProperty property, IEdmStructuredTypeReference resourceType, object resource, ODataDeserializerProvider deserializerProvider, ODataDeserializerContext readContext) { IEdmProperty edmProperty = resourceType.FindProperty(property.Name); string propertyName = property.Name; if (edmProperty != null) { propertyName = EdmLibHelpers.GetClrPropertyName(edmProperty, readContext.Model); } IEdmTypeReference propertyType = edmProperty != null ? edmProperty.Type : null; // open properties have null values EdmTypeKind propertyKind; object value = ConvertValue(property.Value, ref propertyType, deserializerProvider, readContext, out propertyKind); if (propertyKind == EdmTypeKind.Collection) { SetCollectionProperty(resource, edmProperty, value, propertyName); } else { if (!readContext.IsUntyped) { if (propertyKind == EdmTypeKind.Primitive) { value = EdmPrimitiveHelpers.ConvertPrimitiveValue(value, GetPropertyType(resource, propertyName)); } else if (propertyKind == EdmTypeKind.Enum) { value = EnumDeserializationHelpers.ConvertEnumValue(value, GetPropertyType(resource, propertyName)); } } SetProperty(resource, propertyName, value); } }
private static void EnsurePropertyGettingCachePopulated(Type type, IEdmStructuredTypeReference edmType, IEdmModel model, ref ConcurrentDictionary <string, Func <object, object> > propertyGetterCache) { if (propertyGetterCache == null) { propertyGetterCache = _propertyGetterCache.GetOrAdd(type, t => { // Creating all property getters on first access to the type // It will allows us to avoid growing dictionary from 0 to number of properties that means copy data over and over as soon as capacity reached // First get all properties var properties = edmType.StructuredDefinition().Properties().ToList(); // Create dictionary with right capacity var result = new ConcurrentDictionary <string, Func <object, object> >(4 * Environment.ProcessorCount, properties.Count); // Fill dictionary with getters for each property foreach (IEdmProperty property in properties) { var name = EdmLibHelpers.GetClrPropertyName(property, model) ?? property.Name; result.TryAdd(property.Name, CreatePropertyGetter(type, name)); } return(result); }); } }
private void ApplyDeltaResourceSetInNestedProperty(IEdmProperty nestedProperty, object resource, ODataDeltaResourceSetWrapper resourceSetWrapper, ODataDeserializerContext readContext) { Contract.Assert(nestedProperty != null); Contract.Assert(resource != null); Contract.Assert(readContext != null); if (!readContext.IsDeltaOfT) { throw new ODataException("Read context of @odata.delta incorrect"); } ICollection modifiedItems; ICollection deletedItems; ReadDeltaResourceSetInline(resourceSetWrapper, nestedProperty.Type, readContext, out modifiedItems, out deletedItems); IDelta resourceDelta = (IDelta)resource; string propertyName = EdmLibHelpers.GetClrPropertyName(nestedProperty, readContext.Model); resourceDelta.TrySetPropertyCollectionValue(propertyName, modifiedItems); resourceDelta.TrySetDeletedPropertyValue(propertyName, deletedItems); }
internal static object CreateResource(IEdmComplexTypeReference complexType, ODataDeserializerContext readContext) { if (complexType == null) { throw Error.ArgumentNull("complexType"); } if (readContext == null) { throw Error.ArgumentNull("readContext"); } IEdmModel model = readContext.Model; if (model == null) { throw Error.Argument("readContext", SRResources.ModelMissingFromReadContext); } if (readContext.IsUntyped) { return(new EdmComplexObject(complexType)); } else { Type clrType = EdmLibHelpers.GetClrType(complexType, readContext.Model); if (clrType == null) { throw Error.InvalidOperation(SRResources.MappingDoesNotContainEntityType, complexType.FullName()); } if (readContext.IsDeltaOfT) { Type elementType = readContext.ResourceType.GetGenericArguments()[0]; if (elementType != clrType) { // Just create the object for inline complex type return(Activator.CreateInstance(clrType)); } IEnumerable <string> structuralProperties = complexType.StructuralProperties() .Select(edmProperty => EdmLibHelpers.GetClrPropertyName(edmProperty, model)); if (complexType.IsOpen()) { PropertyInfo dynamicDictionaryPropertyInfo = EdmLibHelpers.GetDynamicPropertyDictionary( complexType.StructuredDefinition(), model); return(Activator.CreateInstance(readContext.ResourceType, clrType, structuralProperties, dynamicDictionaryPropertyInfo)); } else { return(Activator.CreateInstance(readContext.ResourceType, clrType, structuralProperties)); } } else { return(Activator.CreateInstance(clrType)); } } }
internal Expression CreatePropertyValueExpressionWithFilter(IEdmStructuredType elementType, IEdmProperty property, Expression source, ExpandedReferenceSelectItem expandItem) { Contract.Assert(elementType != null); Contract.Assert(property != null); Contract.Assert(source != null); FilterClause filterClause = expandItem != null ? expandItem.FilterOption : null; IEdmStructuredType declaringType; IEdmStructuredType currentType = elementType; if (expandItem != null) { foreach (ODataPathSegment segment in expandItem.PathToNavigationProperty) { string currentProperty = String.Empty; PropertySegment propertyAccessPathSegment = segment as PropertySegment; if (propertyAccessPathSegment != null) { IEdmProperty propertyInPath = propertyAccessPathSegment.Property; currentProperty = EdmLibHelpers.GetClrPropertyName(propertyInPath, _model); declaringType = propertyInPath.DeclaringType; Contract.Assert(!String.IsNullOrEmpty(currentProperty), "Property name could not be found on the model."); if (_settings.HandleNullPropagation == HandleNullPropagationOption.True) { // create expression similar to: 'source == null ? null : propertyValue' if (declaringType != currentType) { Type castType = EdmLibHelpers.GetClrType(property.DeclaringType, _model); if (castType == null) { throw new ODataException(Error.Format(SRResources.MappingDoesNotContainResourceType, property.DeclaringType.FullTypeName())); } source = Expression.TypeAs(source, castType); } Expression propertyExpression = Expression.Property(source, currentProperty); Type nullablePropType = TypeHelper.ToNullable(propertyExpression.Type); source = Expression.Condition( test: Expression.Equal(propertyExpression, Expression.Constant(value: null)), ifTrue: Expression.Constant(value: null, type: nullablePropType), ifFalse: propertyExpression); } else { source = Expression.Property(source, currentProperty); } currentType = propertyInPath.Type.ToStructuredType(); } else { TypeSegment typeSegment = segment as TypeSegment; if (typeSegment != null) { Type castType = EdmLibHelpers.GetClrType(typeSegment.EdmType, _model); source = Expression.TypeAs(source, castType); currentType = typeSegment.EdmType as IEdmStructuredType; } } } } // derived property using cast if (currentType != property.DeclaringType) { Type castType = EdmLibHelpers.GetClrType(property.DeclaringType, _model); if (castType == null) { throw new ODataException(Error.Format(SRResources.MappingDoesNotContainResourceType, property.DeclaringType.FullTypeName())); } source = Expression.TypeAs(source, castType); } string propertyName = EdmLibHelpers.GetClrPropertyName(property, _model); PropertyInfo propertyInfo = source.Type.GetProperty(propertyName); Expression propertyValue = Expression.Property(source, propertyInfo); Type nullablePropertyType = TypeHelper.ToNullable(propertyValue.Type); Expression nullablePropertyValue = ExpressionHelpers.ToNullable(propertyValue); if (filterClause != null) { bool isCollection = property.Type.IsCollection(); IEdmTypeReference edmElementType = (isCollection ? property.Type.AsCollection().ElementType() : property.Type); Type clrElementType = EdmLibHelpers.GetClrType(edmElementType, _model); if (clrElementType == null) { throw new ODataException(Error.Format(SRResources.MappingDoesNotContainResourceType, edmElementType.FullName())); } Expression filterResult = nullablePropertyValue; ODataQuerySettings querySettings = new ODataQuerySettings() { HandleNullPropagation = HandleNullPropagationOption.True, }; if (isCollection) { Expression filterSource = nullablePropertyValue; // TODO: Implement proper support for $select/$expand after $apply Expression filterPredicate = FilterBinder.Bind(null, filterClause, clrElementType, _context, querySettings); filterResult = Expression.Call( ExpressionHelperMethods.EnumerableWhereGeneric.MakeGenericMethod(clrElementType), filterSource, filterPredicate); nullablePropertyType = filterResult.Type; } else if (_settings.HandleReferenceNavigationPropertyExpandFilter) { LambdaExpression filterLambdaExpression = FilterBinder.Bind(null, filterClause, clrElementType, _context, querySettings) as LambdaExpression; if (filterLambdaExpression == null) { throw new ODataException(Error.Format(SRResources.ExpandFilterExpressionNotLambdaExpression, property.Name, "LambdaExpression")); } ParameterExpression filterParameter = filterLambdaExpression.Parameters.First(); Expression predicateExpression = new ReferenceNavigationPropertyExpandFilterVisitor(filterParameter, nullablePropertyValue).Visit(filterLambdaExpression.Body); // create expression similar to: 'predicateExpression == true ? nullablePropertyValue : null' filterResult = Expression.Condition( test: predicateExpression, ifTrue: nullablePropertyValue, ifFalse: Expression.Constant(value: null, type: nullablePropertyType)); } if (_settings.HandleNullPropagation == HandleNullPropagationOption.True) { // create expression similar to: 'nullablePropertyValue == null ? null : filterResult' nullablePropertyValue = Expression.Condition( test: Expression.Equal(nullablePropertyValue, Expression.Constant(value: null)), ifTrue: Expression.Constant(value: null, type: nullablePropertyType), ifFalse: filterResult); } else { nullablePropertyValue = filterResult; } } if (_settings.HandleNullPropagation == HandleNullPropagationOption.True) { // create expression similar to: 'source == null ? null : propertyValue' propertyValue = Expression.Condition( test: Expression.Equal(source, Expression.Constant(value: null)), ifTrue: Expression.Constant(value: null, type: nullablePropertyType), ifFalse: nullablePropertyValue); } else { // need to cast this to nullable as EF would fail while materializing if the property is not nullable and source is null. propertyValue = nullablePropertyValue; } return(propertyValue); }
internal Expression CreatePropertyValueExpressionWithFilter(IEdmEntityType elementType, IEdmProperty property, Expression source, FilterClause filterClause) { Contract.Assert(elementType != null); Contract.Assert(property != null); Contract.Assert(source != null); IEdmEntityType declaringType = property.DeclaringType as IEdmEntityType; Contract.Assert(declaringType != null, "only entity types are projected."); // derived property using cast if (elementType != declaringType) { Type castType = EdmLibHelpers.GetClrType(declaringType, _model); if (castType == null) { throw new ODataException(Error.Format(SRResources.MappingDoesNotContainEntityType, declaringType.FullName())); } source = Expression.TypeAs(source, castType); } string propertyName = EdmLibHelpers.GetClrPropertyName(property, _model); Expression propertyValue = Expression.Property(source, propertyName); Type nullablePropertyType = propertyValue.Type.ToNullable(); Expression nullablePropertyValue = ExpressionHelpers.ToNullable(propertyValue); if (filterClause != null && property.Type.IsCollection()) { IEdmTypeReference edmElementType = property.Type.AsCollection().ElementType(); Type clrElementType = EdmLibHelpers.GetClrType(edmElementType, _model); if (clrElementType == null) { throw new ODataException(Error.Format(SRResources.MappingDoesNotContainEntityType, edmElementType.FullName())); } Expression filterSource = typeof(IEnumerable).IsAssignableFrom(source.Type.GetProperty(propertyName).PropertyType) ? Expression.Call( ExpressionHelperMethods.QueryableAsQueryable.MakeGenericMethod(clrElementType), nullablePropertyValue) : nullablePropertyValue; Expression filterPredicate = FilterBinder.Bind( filterClause, clrElementType, _model, _assembliesResolver, _settings); MethodCallExpression filterResult = Expression.Call( ExpressionHelperMethods.QueryableWhereGeneric.MakeGenericMethod(clrElementType), filterSource, filterPredicate); nullablePropertyType = filterResult.Type; if (_settings.HandleNullPropagation == HandleNullPropagationOption.True) { // nullablePropertyValue == null ? null : filterResult nullablePropertyValue = Expression.Condition( test: Expression.Equal(nullablePropertyValue, Expression.Constant(value: null)), ifTrue: Expression.Constant(value: null, type: nullablePropertyType), ifFalse: filterResult); } else { nullablePropertyValue = filterResult; } } if (_settings.HandleNullPropagation == HandleNullPropagationOption.True) { // source == null ? null : propertyValue propertyValue = Expression.Condition( test: Expression.Equal(source, Expression.Constant(value: null)), ifTrue: Expression.Constant(value: null, type: nullablePropertyType), ifFalse: nullablePropertyValue); } else { // need to cast this to nullable as EF would fail while materializing if the property is not nullable and source is null. propertyValue = nullablePropertyValue; } return(propertyValue); }
internal Expression CreatePropertyValueExpressionWithFilter(IEdmEntityType elementType, IEdmProperty property, Expression source, FilterClause filterClause) { Contract.Assert(elementType != null); Contract.Assert(property != null); Contract.Assert(source != null); IEdmEntityType declaringType = property.DeclaringType as IEdmEntityType; Contract.Assert(declaringType != null, "only entity types are projected."); // derived property using cast if (elementType != declaringType) { Type castType = EdmLibHelpers.GetClrType(declaringType, _model); if (castType == null) { throw new ODataException("TODO: " /*Error.Format(SRResources.MappingDoesNotContainResourceType, * declaringType.FullName())*/); } source = Expression.TypeAs(source, castType); } string propertyName = EdmLibHelpers.GetClrPropertyName(property, _model); Expression propertyValue = Expression.Property(source, propertyName); Type nullablePropertyType = propertyValue.Type.ToNullable(); Expression nullablePropertyValue = ExpressionHelpers.ToNullable(propertyValue); Type clrElementType = EdmLibHelpers.GetClrType(elementType, _model); Expression filterSource = null; var interceptorContainer = new InterceptorContainer(clrElementType, _serviceProvider); if ((filterClause != null || interceptorContainer.Any) && property.Type.IsCollection()) { if (clrElementType == null) { throw new ODataException("TODO:" /*Error.Format(SRResources.MappingDoesNotContainResourceType, * edmElementType.FullName())*/); } filterSource = typeof(IEnumerable).IsAssignableFrom(source.Type.GetProperty(propertyName).PropertyType) ? Expression.Call( ExpressionHelperMethods.QueryableAsQueryable.MakeGenericMethod(clrElementType), nullablePropertyValue) : nullablePropertyValue; Expression filterPredicate = FilterBinder.Bind(filterClause, clrElementType, _serviceProvider); MethodCallExpression filterResult = Expression.Call( ExpressionHelperMethods.QueryableWhereGeneric.MakeGenericMethod(clrElementType), filterSource, filterPredicate); nullablePropertyType = filterResult.Type; if (_settings.HandleNullPropagation == HandleNullPropagationOption.True) { // nullablePropertyValue == null ? null : filterResult nullablePropertyValue = Expression.Condition( test: Expression.Equal(nullablePropertyValue, Expression.Constant(value: null)), ifTrue: Expression.Constant(value: null, type: nullablePropertyType), ifFalse: filterResult); } else { nullablePropertyValue = filterResult; } } if ((filterClause != null || interceptorContainer.Any) && property.Type.IsCollection()) { filterSource = typeof(IEnumerable).IsAssignableFrom(source.Type.GetProperty(propertyName).PropertyType) ? Expression.Call( ExpressionHelperMethods.QueryableAsQueryable.MakeGenericMethod(clrElementType), nullablePropertyValue) : nullablePropertyValue; } // TODO: Fix possibly ambiguity resolution if the // implementation class has multiple methods names // "Intercept" var handleNull = false; source = ApplyInterceptors(source, clrElementType, _serviceProvider); //interceptorContainer.ForEach(source, (src, predicate) => //{ // if (filterSource != null) // { // // We have a collection to intercept // ApplyFilterToQuery( // clrElementType, // filterSource, // predicate, // ref nullablePropertyType, // ref nullablePropertyValue); // } // else // { // handleNull = true; // // Apply our predicate locally // nullablePropertyValue = Expression.Condition( // test: Expression.Invoke(predicate, nullablePropertyValue), // ifTrue: propertyValue, // ifFalse: Expression.Constant(value: null, type: nullablePropertyType) // ); // //ApplyFilterToQuery( // // clrElementType, // // propertyValue, // // predicate, // // ref nullablePropertyType, // // ref nullablePropertyValue); // } //}); if (_settings.HandleNullPropagation == HandleNullPropagationOption.True) { // source == null ? null : propertyValue propertyValue = Expression.Condition( test: Expression.Equal(source, Expression.Constant(value: null)), ifTrue: Expression.Constant(value: null, type: nullablePropertyType), ifFalse: nullablePropertyValue); } else { // need to cast this to nullable as EF would fail while materializing if the property is not nullable and source is null. propertyValue = nullablePropertyValue; } return(propertyValue); }
private Expression CreateEntitySetAggregateExpression( ParameterExpression accum, EntitySetAggregateExpression expression, Type baseType) { // Should return following expression // $it => $it.AsQueryable() // .SelectMany($it => $it.SomeEntitySet) // .GroupBy($gr => new Object()) // .Select($p => new DynamicTypeWrapper() // { // AliasOne = $p.AsQueryable().AggMethodOne($it => $it.SomePropertyOfSomeEntitySet), // AliasTwo = $p.AsQueryable().AggMethodTwo($it => $it.AnotherPropertyOfSomeEntitySet), // ... // AliasN = ... , // A nested expression of this same format. // ... // }) List <MemberAssignment> wrapperTypeMemberAssignments = new List <MemberAssignment>(); var asQueryableMethod = ExpressionHelperMethods.QueryableAsQueryable.MakeGenericMethod(baseType); Expression asQueryableExpression = Expression.Call(null, asQueryableMethod, accum); // Create lambda to access the entity set from expression var source = BindAccessor(expression.Expression.Source); string propertyName = EdmLibHelpers.GetClrPropertyName(expression.Expression.NavigationProperty, Model); var property = Expression.Property(source, propertyName); var baseElementType = source.Type; var selectedElementType = property.Type.GenericTypeArguments.Single(); // Create method to get property collections to aggregate MethodInfo selectManyMethod = ExpressionHelperMethods.EnumerableSelectManyGeneric.MakeGenericMethod(baseElementType, selectedElementType); // Create the lambda that acceses the property in the selectMany clause. var selectManyParam = Expression.Parameter(baseElementType, "$it"); var propertyExpression = Expression.Property(selectManyParam, expression.Expression.NavigationProperty.Name); var selectManyLambda = Expression.Lambda(propertyExpression, selectManyParam); // Get expression to get collection of entities var entitySet = Expression.Call(null, selectManyMethod, asQueryableExpression, selectManyLambda); // Getting method and lambda expression of groupBy var groupKeyType = typeof(object); MethodInfo groupByMethod = ExpressionHelperMethods.EnumerableGroupByGeneric.MakeGenericMethod(selectedElementType, groupKeyType); var groupByLambda = Expression.Lambda( Expression.New(groupKeyType), Expression.Parameter(selectedElementType, "$gr")); // Group entities in a single group to apply select var groupedEntitySet = Expression.Call(null, groupByMethod, entitySet, groupByLambda); var groupingType = typeof(IGrouping <,>).MakeGenericType(groupKeyType, selectedElementType); ParameterExpression innerAccum = Expression.Parameter(groupingType, "$p"); // Nested properties // Create dynamicTypeWrapper to encapsulate the aggregate result var properties = new List <NamedPropertyExpression>(); foreach (var aggExpression in expression.Children) { properties.Add(new NamedPropertyExpression(Expression.Constant(aggExpression.Alias), CreateAggregationExpression(innerAccum, aggExpression, selectedElementType))); } var nestedResultType = typeof(EntitySetAggregationWrapper); var wrapperProperty = nestedResultType.GetProperty("Container"); wrapperTypeMemberAssignments.Add(Expression.Bind(wrapperProperty, AggregationPropertyContainer.CreateNextNamedPropertyContainer(properties))); var initializedMember = Expression.MemberInit(Expression.New(nestedResultType), wrapperTypeMemberAssignments); var selectLambda = Expression.Lambda(initializedMember, innerAccum); // Get select method MethodInfo selectMethod = ExpressionHelperMethods.EnumerableSelectGeneric.MakeGenericMethod( groupingType, selectLambda.Body.Type); return(Expression.Call(null, selectMethod, groupedEntitySet, selectLambda)); }
/// <summary> /// Creates a new instance of the backing CLR object for the given entity type. /// </summary> /// <param name="entityType">The EDM type of the entity to create.</param> /// <param name="readContext">The deserializer context.</param> /// <returns>The created CLR object.</returns> public virtual object CreateEntityResource(IEdmEntityTypeReference entityType, ODataDeserializerContext readContext) { if (readContext == null) { throw Error.ArgumentNull("readContext"); } if (entityType == null) { throw Error.ArgumentNull("entityType"); } IEdmModel model = readContext.Model; if (model == null) { throw Error.Argument("readContext", SRResources.ModelMissingFromReadContext); } if (readContext.IsUntyped) { return(new EdmEntityObject(entityType)); } else { Type clrType = EdmLibHelpers.GetClrType(entityType, model); if (clrType == null) { throw new ODataException( Error.Format(SRResources.MappingDoesNotContainEntityType, entityType.FullName())); } if (readContext.IsDeltaOfT) { IEnumerable <string> structuralProperties = entityType.StructuralProperties() .Select(edmProperty => EdmLibHelpers.GetClrPropertyName(edmProperty, model)); return(Activator.CreateInstance(readContext.ResourceType, clrType, structuralProperties)); } else { return(Activator.CreateInstance(clrType)); } } }
/// <summary> /// Creates a new instance of the backing CLR object for the given resource type. /// </summary> /// <param name="structuredType">The EDM type of the resource to create.</param> /// <param name="readContext">The deserializer context.</param> /// <returns>The created CLR object.</returns> public virtual object CreateResourceInstance(IEdmStructuredTypeReference structuredType, ODataDeserializerContext readContext) { if (readContext == null) { throw Error.ArgumentNull("readContext"); } if (structuredType == null) { throw Error.ArgumentNull("structuredType"); } IEdmModel model = readContext.Model; if (model == null) { throw Error.Argument("readContext", SRResources.ModelMissingFromReadContext); } if (readContext.IsUntyped) { if (structuredType.IsEntity()) { return(new EdmEntityObject(structuredType.AsEntity())); } return(new EdmComplexObject(structuredType.AsComplex())); } else { Type clrType = EdmLibHelpers.GetClrType(structuredType, model); if (clrType == null) { throw new ODataException( Error.Format(SRResources.MappingDoesNotContainResourceType, structuredType.FullName())); } if (readContext.IsDeltaOfT) { IEnumerable <string> structuralProperties = structuredType.StructuralProperties() .Select(edmProperty => EdmLibHelpers.GetClrPropertyName(edmProperty, model)); if (structuredType.IsOpen()) { PropertyInfo dynamicDictionaryPropertyInfo = EdmLibHelpers.GetDynamicPropertyDictionary( structuredType.StructuredDefinition(), model); return(Activator.CreateInstance(readContext.ResourceType, clrType, structuralProperties, dynamicDictionaryPropertyInfo)); } else { return(Activator.CreateInstance(readContext.ResourceType, clrType, structuralProperties)); } } else { return(Activator.CreateInstance(clrType)); } } }
internal Expression CreatePropertyValueExpressionWithFilter(IEdmEntityType elementType, IEdmProperty property, Expression source, FilterClause filterClause) { Contract.Assert(elementType != null); Contract.Assert(property != null); Contract.Assert(source != null); IEdmEntityType declaringType = property.DeclaringType as IEdmEntityType; Contract.Assert(declaringType != null, "only entity types are projected."); // derived property using cast if (elementType != declaringType) { Type castType = EdmLibHelpers.GetClrType(declaringType, _model); if (castType == null) { throw new ODataException(Error.Format(SRResources.MappingDoesNotContainResourceType, declaringType.FullName())); } source = Expression.TypeAs(source, castType); } string propertyName = EdmLibHelpers.GetClrPropertyName(property, _model); Expression propertyValue = Expression.Property(source, propertyName); Type nullablePropertyType = TypeHelper.ToNullable(propertyValue.Type); Expression nullablePropertyValue = ExpressionHelpers.ToNullable(propertyValue); if (filterClause != null) { bool isCollection = property.Type.IsCollection(); IEdmTypeReference edmElementType = (isCollection ? property.Type.AsCollection().ElementType() : property.Type); Type clrElementType = EdmLibHelpers.GetClrType(edmElementType, _model); if (clrElementType == null) { throw new ODataException(Error.Format(SRResources.MappingDoesNotContainResourceType, edmElementType.FullName())); } Expression filterResult = nullablePropertyValue; ODataQuerySettings querySettings = new ODataQuerySettings() { HandleNullPropagation = HandleNullPropagationOption.True, }; if (isCollection) { Expression filterSource = typeof(IEnumerable).IsAssignableFrom(source.Type.GetProperty(propertyName).PropertyType) ? Expression.Call( ExpressionHelperMethods.QueryableAsQueryable.MakeGenericMethod(clrElementType), nullablePropertyValue) : nullablePropertyValue; // TODO: Implement proper support for $select/$expand after $apply Expression filterPredicate = FilterBinder.Bind(null, filterClause, clrElementType, _context, querySettings); filterResult = Expression.Call( ExpressionHelperMethods.QueryableWhereGeneric.MakeGenericMethod(clrElementType), filterSource, filterPredicate); nullablePropertyType = filterResult.Type; } else if (_settings.HandleReferenceNavigationPropertyExpandFilter) { LambdaExpression filterLambdaExpression = FilterBinder.Bind(null, filterClause, clrElementType, _context, querySettings) as LambdaExpression; if (filterLambdaExpression == null) { throw new ODataException(Error.Format(SRResources.ExpandFilterExpressionNotLambdaExpression, property.Name, "LambdaExpression")); } ParameterExpression filterParameter = filterLambdaExpression.Parameters.First(); Expression predicateExpression = new ReferenceNavigationPropertyExpandFilterVisitor(filterParameter, nullablePropertyValue).Visit(filterLambdaExpression.Body); // create expression similar to: 'predicateExpression == true ? nullablePropertyValue : null' filterResult = Expression.Condition( test: predicateExpression, ifTrue: nullablePropertyValue, ifFalse: Expression.Constant(value: null, type: nullablePropertyType)); } if (_settings.HandleNullPropagation == HandleNullPropagationOption.True) { // create expression similar to: 'nullablePropertyValue == null ? null : filterResult' nullablePropertyValue = Expression.Condition( test: Expression.Equal(nullablePropertyValue, Expression.Constant(value: null)), ifTrue: Expression.Constant(value: null, type: nullablePropertyType), ifFalse: filterResult); } else { nullablePropertyValue = filterResult; } } if (_settings.HandleNullPropagation == HandleNullPropagationOption.True) { // create expression similar to: 'source == null ? null : propertyValue' propertyValue = Expression.Condition( test: Expression.Equal(source, Expression.Constant(value: null)), ifTrue: Expression.Constant(value: null, type: nullablePropertyType), ifFalse: nullablePropertyValue); } else { // need to cast this to nullable as EF would fail while materializing if the property is not nullable and source is null. propertyValue = nullablePropertyValue; } return(propertyValue); }
internal static void ApplyProperty(ODataProperty property, IEdmStructuredTypeReference resourceType, object resource, ODataDeserializerProvider deserializerProvider, ODataDeserializerContext readContext) { IEdmProperty edmProperty; // Extract edmProperty using a Case-Sensitive match edmProperty = resourceType.FindProperty(property.Name); if (readContext != null && !readContext.DisableCaseInsensitiveRequestPropertyBinding && edmProperty == null) { // if edmProperty is null, we try a Case-Insensitive match. bool propertyMatched = false; IEnumerable <IEdmStructuralProperty> structuralProperties = resourceType.StructuralProperties(); foreach (IEdmStructuralProperty structuralProperty in structuralProperties) { if (structuralProperty.Name.Equals(property.Name, StringComparison.OrdinalIgnoreCase)) { // We throw an exception when we have more than 1 case-insensitive matches and no case sensitive matches. if (propertyMatched) { throw new ODataException(Error.Format(SRResources.CannotDeserializeUnknownProperty, property.Name, resourceType.Definition)); } propertyMatched = true; edmProperty = resourceType.FindProperty(structuralProperty.Name); } } } bool isDynamicProperty = false; string propertyName = property.Name; if (edmProperty != null) { propertyName = EdmLibHelpers.GetClrPropertyName(edmProperty, readContext.Model); } else { IEdmStructuredType structuredType = resourceType.StructuredDefinition(); isDynamicProperty = structuredType != null && structuredType.IsOpen; } if (!isDynamicProperty && edmProperty == null) { throw new ODataException( Error.Format(SRResources.CannotDeserializeUnknownProperty, property.Name, resourceType.Definition)); } // dynamic properties have null values IEdmTypeReference propertyType = edmProperty != null ? edmProperty.Type : null; EdmTypeKind propertyKind; object value = ConvertValue(property.Value, ref propertyType, deserializerProvider, readContext, out propertyKind); if (isDynamicProperty) { SetDynamicProperty(resource, resourceType, propertyKind, propertyName, value, propertyType, readContext.Model); } else { SetDeclaredProperty(resource, propertyKind, propertyName, value, edmProperty, readContext); } }