Пример #1
0
        private Expression CreateTotalCountExpression(Expression source, ExpandedNavigationSelectItem expandItem)
        {
            Expression countExpression = Expression.Constant(null, typeof(long?));

            if (expandItem.CountOption == null || !expandItem.CountOption.Value)
            {
                return(countExpression);
            }

            Type elementType;

            if (!source.Type.IsCollection(out elementType))
            {
                return(countExpression);
            }

            MethodInfo countMethod;

            if (typeof(IQueryable).IsAssignableFrom(source.Type))
            {
                countMethod = ExpressionHelperMethods.QueryableCountGeneric.MakeGenericMethod(elementType);
            }
            else
            {
                countMethod = ExpressionHelperMethods.EnumerableCountGeneric.MakeGenericMethod(elementType);
            }

            // call Count() method.
            countExpression = Expression.Call(null, countMethod, new[] { source });

            if (_settings.HandleNullPropagation == HandleNullPropagationOption.True)
            {
                // source == null ? null : countExpression
                return(Expression.Condition(
                           test: Expression.Equal(source, Expression.Constant(null)),
                           ifTrue: Expression.Constant(null, typeof(long?)),
                           ifFalse: ExpressionHelpers.ToNullable(countExpression)));
            }
            else
            {
                return(countExpression);
            }
        }
Пример #2
0
        private Expression BindCountNode(CountNode node)
        {
            Expression source          = Bind(node.Source);
            Expression countExpression = Expression.Constant(null, typeof(long?));
            Type       elementType;

            if (!TypeHelper.IsCollection(source.Type, out elementType))
            {
                return(countExpression);
            }

            MethodInfo countMethod;

            if (typeof(IQueryable).IsAssignableFrom(source.Type))
            {
                countMethod = ExpressionHelperMethods.QueryableCountGeneric.MakeGenericMethod(elementType);
            }
            else
            {
                countMethod = ExpressionHelperMethods.EnumerableCountGeneric.MakeGenericMethod(elementType);
            }

            // call Count() method.
            countExpression = Expression.Call(null, countMethod, new[] { source });

            if (QuerySettings.HandleNullPropagation == HandleNullPropagationOption.True)
            {
                // source == null ? null : countExpression
                return(Expression.Condition(
                           test: Expression.Equal(source, Expression.Constant(null)),
                           ifTrue: Expression.Constant(null, typeof(long?)),
                           ifFalse: ExpressionHelpers.ToNullable(countExpression)));
            }
            else
            {
                return(countExpression);
            }
        }
Пример #3
0
        private Expression BuildPropertyContainer(IEdmEntityType elementType, Expression source,
                                                  Dictionary <IEdmNavigationProperty, ExpandedNavigationSelectItem> propertiesToExpand,
                                                  ISet <IEdmStructuralProperty> propertiesToInclude, ISet <IEdmStructuralProperty> autoSelectedProperties, bool isSelectingOpenTypeSegments)
        {
            IList <NamedPropertyExpression> includedProperties = new List <NamedPropertyExpression>();

            foreach (KeyValuePair <IEdmNavigationProperty, ExpandedNavigationSelectItem> kvp in propertiesToExpand)
            {
                IEdmNavigationProperty       propertyToExpand = kvp.Key;
                ExpandedNavigationSelectItem expandItem       = kvp.Value;
                SelectExpandClause           projection       = expandItem.SelectAndExpand;

                Expression propertyName  = CreatePropertyNameExpression(elementType, propertyToExpand, source);
                Expression propertyValue = CreatePropertyValueExpressionWithFilter(elementType, propertyToExpand, source,
                                                                                   expandItem.FilterOption);
                Expression nullCheck = GetNullCheckExpression(propertyToExpand, propertyValue, projection);

                Expression countExpression = CreateTotalCountExpression(propertyValue, expandItem);

                // projection can be null if the expanded navigation property is not further projected or expanded.
                if (projection != null)
                {
                    propertyValue = ProjectAsWrapper(propertyValue, projection, propertyToExpand.ToEntityType(), expandItem.NavigationSource as IEdmEntitySet,
                                                     expandItem);
                }

                NamedPropertyExpression propertyExpression = new NamedPropertyExpression(propertyName, propertyValue);
                if (projection != null)
                {
                    if (!propertyToExpand.Type.IsCollection())
                    {
                        propertyExpression.NullCheck = nullCheck;
                    }
                    else if (_settings.PageSize != null)
                    {
                        propertyExpression.PageSize = _settings.PageSize.Value;
                    }
                    propertyExpression.TotalCount  = countExpression;
                    propertyExpression.CountOption = expandItem.CountOption;
                }

                includedProperties.Add(propertyExpression);
            }

            foreach (IEdmStructuralProperty propertyToInclude in propertiesToInclude)
            {
                Expression propertyName  = CreatePropertyNameExpression(elementType, propertyToInclude, source);
                Expression propertyValue = CreatePropertyValueExpression(elementType, propertyToInclude, source);
                includedProperties.Add(new NamedPropertyExpression(propertyName, propertyValue));
            }

            foreach (IEdmStructuralProperty propertyToInclude in autoSelectedProperties)
            {
                Expression propertyName  = CreatePropertyNameExpression(elementType, propertyToInclude, source);
                Expression propertyValue = CreatePropertyValueExpression(elementType, propertyToInclude, source);
                includedProperties.Add(new NamedPropertyExpression(propertyName, propertyValue)
                {
                    AutoSelected = true
                });
            }

            if (isSelectingOpenTypeSegments)
            {
                var dynamicPropertyDictionary = EdmLibHelpers.GetDynamicPropertyDictionary(elementType, _model);

                Expression propertyName          = Expression.Constant(dynamicPropertyDictionary.Name);
                Expression propertyValue         = Expression.Property(source, dynamicPropertyDictionary.Name);
                Expression nullablePropertyValue = ExpressionHelpers.ToNullable(propertyValue);
                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: propertyValue.Type.ToNullable()),
                        ifFalse: nullablePropertyValue);
                }
                else
                {
                    propertyValue = nullablePropertyValue;
                }

                includedProperties.Add(new NamedPropertyExpression(propertyName, propertyValue));
            }

            // create a property container that holds all these property names and values.
            return(PropertyContainer.CreatePropertyContainer(includedProperties));
        }
Пример #4
0
        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);

            if (filterClause != null && property.Type.IsCollection())
            {
                IEdmTypeReference edmElementType = property.Type.AsCollection().ElementType();
                Type clrElementType = EdmLibHelpers.GetClrType(edmElementType, _model);
                if (clrElementType == null)
                {
                    throw new ODataException("TODO:" /*Error.Format(SRResources.MappingDoesNotContainResourceType,
                                                      * 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, /*_context.RequestContainer*/ null);
                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 (!property.Type.IsCollection())
            {
                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);
        }
Пример #5
0
        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);
        }