private static Expression ApplyInterceptors(Expression source, Type elementType, IServiceProvider serviceProvider) { var interceptorContainer = new InterceptorContainer(elementType, serviceProvider); if (interceptorContainer.Any) { var parameterExpression = source as ParameterExpression; if (parameterExpression != null) { source = ApplyInterceptorsToProperty(source, elementType, interceptorContainer); } var memberExpression = source as MemberExpression; if (memberExpression != null) { var property = memberExpression.Member as PropertyInfo; if (property == null) { var owningType = memberExpression.Type.DeclaringType; var propertyName = memberExpression.Member.Name; property = owningType.GetProperty(propertyName); } source = typeof(IEnumerable).IsAssignableFrom(property.PropertyType) ? ApplyInterceptorsToCollection(source, elementType, interceptorContainer) : ApplyInterceptorsToProperty(source, elementType, interceptorContainer); } } return(source); }
private static Expression ApplyInterceptorsToCollection(Expression source, Type elementType, InterceptorContainer interceptorContainer) { interceptorContainer.ForEach(source, (src, predicate) => { var filterResult = Expression.Call( ExpressionHelperMethods.EnumerableWhereGeneric.MakeGenericMethod(elementType), src, predicate); source = filterResult; }); return(source); }
private static Expression ApplyInterceptorsToProperty(Expression source, Type elementType, InterceptorContainer interceptorContainer) { //return source; interceptorContainer.ForEach(source, (src, predicate) => { //var m = source as MemberExpression; //var p = m.Member as PropertyInfo; ////var newExp = PredicateRewriter.RewriteLambda(predicate, src.ToString()); //var methodCall = predicate.Body as MethodCallExpression; //var n = predicate.Substitute(, source); //var x = Expression.Lambda(predicate.Body, new[] { Expression.Parameter(m.Expression.Type) }.ToList()); var rewrittenExpression = new ParameterReplacerVisitor(predicate.Parameters[0].Name, src).Visit(predicate.Body); var filterResult = Expression.Condition( test: rewrittenExpression, ifTrue: src, ifFalse: Expression.Constant(elementType.GetDefault(), elementType), type: elementType); source = filterResult; }); return(source); }
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); }