Example #1
0
        private MethodCallExpression ApplyAggregate(Expression source, AggregateTransformationNode transformation)
        {
            Type sourceType = OeExpressionHelper.GetCollectionItemType(source.Type);
            ParameterExpression sourceParameter = Expression.Parameter(sourceType);
            ParameterExpression lambdaParameter = sourceParameter;

            var  expressions = new List <Expression>();
            bool isGroupBy   = sourceType.GetGenericTypeDefinition() == typeof(IGrouping <,>);

            if (isGroupBy)
            {
                PropertyInfo     keyProperty = sourceType.GetProperty(nameof(IGrouping <Object, Object> .Key));
                MemberExpression key         = Expression.Property(sourceParameter, keyProperty);
                expressions.Add(key);

                lambdaParameter = Expression.Parameter(sourceType.GetGenericArguments()[1]);
            }

            var visitor = CreateVisitor(lambdaParameter);

            foreach (AggregateExpressionBase aggExpressionBase in transformation.AggregateExpressions)
            {
                if (aggExpressionBase is AggregateExpression aggExpression)
                {
                    MethodCallExpression aggCallExpression;
                    if (aggExpression.Method == AggregationMethod.VirtualPropertyCount)
                    {
                        aggCallExpression = CountExpression(sourceParameter);
                    }
                    else
                    {
                        Expression expression = visitor.TranslateNode(aggExpression.Expression);
                        if (isGroupBy && expression is MemberExpression propertyExpression)
                        {
                            MemberExpression?keyPropertyExpression = FindInGroupByKey(source, expressions[0], propertyExpression);
                            if (keyPropertyExpression != null)
                            {
                                expression = keyPropertyExpression;
                            }
                        }
                        LambdaExpression aggLambda = Expression.Lambda(expression, lambdaParameter);
                        aggCallExpression = AggCallExpression(aggExpression.Method, sourceParameter, aggLambda);
                    }
                    expressions.Add(aggCallExpression);
                    _aggProperties.Add(CreateEdmProperty(aggCallExpression.Type, aggExpression.Alias, false));
                }
                else
                {
                    throw new NotSupportedException("Unknown aggregate expression type " + aggExpressionBase.GetType().Name);
                }
            }

            NewExpression    newExpression    = OeExpressionHelper.CreateTupleExpression(expressions);
            MethodInfo       selectMethodInfo = OeMethodInfoHelper.GetSelectMethodInfo(sourceType, newExpression.Type);
            LambdaExpression lambda           = Expression.Lambda(newExpression, sourceParameter);

            return(Expression.Call(selectMethodInfo, source, lambda));
        }
        private static LambdaExpression GetSelectManyCollectionSelector(LambdaExpression groupJoinResultSelect)
        {
            ParameterExpression parameter   = Expression.Parameter(groupJoinResultSelect.ReturnType);
            MemberExpression    innerSource = Expression.Property(parameter, parameter.Type.GetProperty(nameof(Tuple <Object, Object> .Item2)));
            Type innerType = OeExpressionHelper.GetCollectionItemType(innerSource.Type);
            MethodCallExpression defaultIfEmptyCall = Expression.Call(OeMethodInfoHelper.GetDefaultIfEmptyMethodInfo(innerType), innerSource);

            return(Expression.Lambda(defaultIfEmptyCall, parameter));
        }
        public Expression Build(Expression source, IReadOnlyList <OeSkipTokenNameValue> skipTokenNameValues, OrderByClause uniqueOrderBy)
        {
            OrderProperty[] orderProperties = CreateOrderProperies(source, skipTokenNameValues, uniqueOrderBy);
            Expression      filter          = CreateFilterExpression(_isDatabaseNullHighestValue, orderProperties);

            LambdaExpression lambda          = Expression.Lambda(filter, _visitor.Parameter);
            MethodInfo       whereMethodInfo = OeMethodInfoHelper.GetWhereMethodInfo(_visitor.Parameter.Type);

            return(Expression.Call(whereMethodInfo, source, lambda));
        }
Example #4
0
        private static MethodCallExpression CreateWhereExpression(ParameterExpression sourceParameter, Expression subquery, IEdmNavigationProperty edmNavigationProperty)
        {
            Type             subqueryType      = OeExpressionHelper.GetCollectionItemType(subquery.Type);
            var              subqueryParameter = Expression.Parameter(subqueryType, subqueryType.Name);
            BinaryExpression joinExpression    = GetJoinExpression(sourceParameter, subqueryParameter, edmNavigationProperty);
            LambdaExpression predicate         = Expression.Lambda(joinExpression, subqueryParameter);

            MethodInfo whereMethodInfo = OeMethodInfoHelper.GetWhereMethodInfo(subqueryType);

            return(Expression.Call(whereMethodInfo, subquery, predicate));
        }
Example #5
0
        private static MethodCallExpression CountDistinctExpression(ParameterExpression sourceParameter, LambdaExpression lambda)
        {
            MethodInfo           selectMetodInfo = OeMethodInfoHelper.GetSelectMethodInfo(lambda.Parameters[0].Type, lambda.ReturnType);
            MethodCallExpression selectCall      = Expression.Call(selectMetodInfo, sourceParameter, lambda);

            MethodInfo           distinctMethodInfo = OeMethodInfoHelper.GetDistinctMethodInfo(lambda.ReturnType);
            MethodCallExpression distinctCall       = Expression.Call(distinctMethodInfo, selectCall);

            MethodInfo countMethodInfo = OeMethodInfoHelper.GetCountMethodInfo(lambda.ReturnType);

            return(Expression.Call(countMethodInfo, distinctCall));
        }
Example #6
0
        private MethodCallExpression ApplyGroupBy(Expression source, GroupByTransformationNode transformation)
        {
            Type sourceType = OeExpressionHelper.GetCollectionItemType(source.Type);
            ParameterExpression sourceParameter = Expression.Parameter(sourceType);
            var visitor = CreateVisitor(sourceParameter);

            var expressions = new List <Expression>();

            foreach (GroupByPropertyNode node in transformation.GroupingProperties)
            {
                if (node.ChildTransformations != null && node.ChildTransformations.Count > 0)
                {
                    for (int i = 0; i < node.ChildTransformations.Count; i++)
                    {
                        Expression e = visitor.TranslateNode(node.ChildTransformations[i].Expression);
                        expressions.Add(e);

                        String aliasName = node.Name + "_" + node.ChildTransformations[i].Name;
                        _aggProperties.Add(CreateEdmProperty(visitor.EdmModel, e.Type, aliasName, true));
                    }
                }
                else
                {
                    Expression e = visitor.TranslateNode(node.Expression);
                    expressions.Add(e);

                    _aggProperties.Add(CreateEdmProperty(visitor.EdmModel, e.Type, node.Name, true));
                }
            }

            NewExpression    newExpression = OeExpressionHelper.CreateTupleExpression(expressions);
            LambdaExpression lambda        = Expression.Lambda(newExpression, sourceParameter);

            MethodInfo           groupByMethodInfo = OeMethodInfoHelper.GetGroupByMethodInfo(sourceType, newExpression.Type);
            MethodCallExpression groupByCall       = Expression.Call(groupByMethodInfo, source, lambda);

            var aggTransformation = (AggregateTransformationNode)transformation.ChildTransformations;

            if (aggTransformation == null)
            {
                expressions.Clear();
                sourceType      = OeExpressionHelper.GetCollectionItemType(groupByCall.Type);
                sourceParameter = Expression.Parameter(sourceType);
                expressions.Add(Expression.Property(sourceParameter, nameof(IGrouping <Object, Object> .Key)));
                newExpression = OeExpressionHelper.CreateTupleExpression(expressions);

                MethodInfo selectMethodInfo = OeMethodInfoHelper.GetSelectMethodInfo(sourceType, newExpression.Type);
                lambda = Expression.Lambda(newExpression, sourceParameter);
                return(Expression.Call(selectMethodInfo, groupByCall, lambda));
            }

            return(ApplyAggregate(groupByCall, aggTransformation));
        }
 private static MethodInfo GetOrderByMethodInfo(Expression source, OrderByDirection direction, Type sourceType, Type keyType)
 {
     if (source.Type.GetGenericTypeDefinition() == typeof(IOrderedEnumerable <>))
     {
         return(direction == OrderByDirection.Ascending ?
                OeMethodInfoHelper.GetThenByMethodInfo(sourceType, keyType) :
                OeMethodInfoHelper.GetThenByDescendingMethodInfo(sourceType, keyType));
     }
     else
     {
         return(direction == OrderByDirection.Ascending ?
                OeMethodInfoHelper.GetOrderByMethodInfo(sourceType, keyType) :
                OeMethodInfoHelper.GetOrderByDescendingMethodInfo(sourceType, keyType));
     }
 }
Example #8
0
        private static MethodCallExpression AggCallExpression(AggregationMethod aggMethod, ParameterExpression sourceParameter, LambdaExpression lambda)
        {
            String methodName;

            switch (aggMethod)
            {
            case AggregationMethod.Average:
                methodName = nameof(Enumerable.Average);
                break;

            case AggregationMethod.CountDistinct:
                return(CountDistinctExpression(sourceParameter, lambda));

            case AggregationMethod.Max:
                methodName = nameof(Enumerable.Max);
                break;

            case AggregationMethod.Min:
                methodName = nameof(Enumerable.Min);
                break;

            case AggregationMethod.Sum:
                methodName = nameof(Enumerable.Sum);
                break;

            case AggregationMethod.VirtualPropertyCount:
                return(CountExpression(sourceParameter));

            default:
                throw new NotSupportedException();
            }

            MethodInfo closeMethod;
            MethodInfo openMethod = OeMethodInfoHelper.GetAggMethodInfo(methodName, lambda.ReturnType);

            if (openMethod.GetGenericArguments().Length == 1)
            {
                closeMethod = openMethod.MakeGenericMethod(lambda.Parameters[0].Type);
            }
            else
            {
                closeMethod = openMethod.MakeGenericMethod(lambda.Parameters[0].Type, lambda.ReturnType);
            }

            return(Expression.Call(closeMethod, sourceParameter, lambda));
        }
Example #9
0
        public static MethodCallExpression Build(Expression outer, Expression inner, ExpandedNavigationSelectItem item, ODataPath odataPath, OeExpressionBuilder expressionBuilder)
        {
            var segment = (NavigationPropertySegment)item.PathToNavigationProperty.LastSegment;

            Type       outerType      = OeExpressionHelper.GetCollectionItemType(outer.Type);
            var        outerParameter = Expression.Parameter(outerType, outerType.Name);
            Expression subquery       = CreateWhereExpression(outerParameter, inner, segment.NavigationProperty);

            subquery = expressionBuilder.ApplyOrderBy(subquery, item.OrderByOption);
            subquery = expressionBuilder.ApplySkip(subquery, item.SkipOption, odataPath);
            subquery = expressionBuilder.ApplyTake(subquery, item.TopOption, odataPath);

            Type       innerType            = OeExpressionHelper.GetCollectionItemType(inner.Type);
            MethodInfo selectManyMethdoInfo = OeMethodInfoHelper.GetSelectManyMethodInfo(outerType, innerType);

            return(Expression.Call(selectManyMethdoInfo, outer, Expression.Lambda(subquery, outerParameter)));
        }
Example #10
0
        private MethodCallExpression Build(Expression outerSource, Expression innerSource, IReadOnlyList <IEdmNavigationProperty> joinPath, IEdmNavigationProperty navigationProperty, bool manyToMany)
        {
            Type outerType = OeExpressionHelper.GetCollectionItemType(outerSource.Type);
            Type innerType = OeExpressionHelper.GetCollectionItemType(innerSource.Type);

            (LambdaExpression groupJoinOuterKeySelector, LambdaExpression groupJoinInnerKeySelector) = GetJoinKeySelector(outerType, innerType, joinPath, navigationProperty);
            LambdaExpression groupJoinResultSelect = GetGroupJoinResultSelector(outerType, innerType, manyToMany);

            MethodInfo           groupJoinMethodInfo = OeMethodInfoHelper.GetGroupJoinMethodInfo(outerType, innerType, groupJoinOuterKeySelector.ReturnType, groupJoinResultSelect.ReturnType);
            MethodCallExpression groupJoinCall       = Expression.Call(groupJoinMethodInfo, outerSource, innerSource, groupJoinOuterKeySelector, groupJoinInnerKeySelector, groupJoinResultSelect);

            LambdaExpression selectManySource         = GetSelectManyCollectionSelector(groupJoinResultSelect);
            LambdaExpression selectManyResultSelector = GetSelectManyResultSelector(groupJoinResultSelect);

            MethodInfo selectManyMethodInfo = OeMethodInfoHelper.GetSelectManyMethodInfo(groupJoinResultSelect.ReturnType, innerType, selectManyResultSelector.ReturnType);

            return(Expression.Call(selectManyMethodInfo, groupJoinCall, selectManySource, selectManyResultSelector));
        }
Example #11
0
        private MethodCallExpression ApplyFilter(Expression source, FilterTransformationNode transformation)
        {
            Type sourceType = OeExpressionHelper.GetCollectionItemType(source.Type);
            ParameterExpression sourceParameter = Expression.Parameter(sourceType);

            var visitor = CreateVisitor(sourceParameter);

            if (_aggProperties.Count > 0)
            {
                visitor.TuplePropertyByAliasName = GetTuplePropertyByAliasName;
            }
            Expression e = visitor.TranslateNode(transformation.FilterClause.Expression);

            MethodInfo       whereMethodInfo = OeMethodInfoHelper.GetWhereMethodInfo(sourceParameter.Type);
            LambdaExpression lambda          = Expression.Lambda(e, sourceParameter);

            return(Expression.Call(whereMethodInfo, source, lambda));
        }
Example #12
0
            protected override Expression VisitNew(NewExpression node)
            {
                var arguments = new Expression[node.Arguments.Count];

                for (int i = 0; i < arguments.Length; i++)
                {
                    Expression argument = base.Visit(node.Arguments[i]);
                    if (argument is MethodCallExpression call && call.Type.GetTypeInfo().IsGenericType&& call.Type.GetGenericTypeDefinition() == typeof(IOrderedEnumerable <>))
                    {
                        Type                type             = call.Type.GetGenericArguments()[0];
                        MethodInfo          selectMethodInfo = OeMethodInfoHelper.GetSelectMethodInfo(type, type);
                        ParameterExpression parameter        = Expression.Parameter(type);
                        argument = Expression.Call(selectMethodInfo, call, Expression.Lambda(parameter, parameter));
                    }
                    arguments[i] = argument;
                }
                return(OeExpressionHelper.CreateTupleExpression(arguments));
            }
        internal MethodCallExpression BuildExpandCount(Expression outer, Expression inner, OeNavigationSelectItem navigationItem)
        {
            IEdmNavigationProperty navigationProperty = navigationItem.EdmProperty;

            if (navigationItem.EdmProperty.ContainsTarget)
            {
                throw new InvalidOperationException("Expand cout for many-tomany not supported");
            }

            Type outerType = OeExpressionHelper.GetCollectionItemType(outer.Type);
            Type innerType = OeExpressionHelper.GetCollectionItemType(inner.Type);

            ParameterExpression outerParameter = Expression.Parameter(outerType, outerType.Name);
            IReadOnlyList <IEdmNavigationProperty> joinPath = navigationItem.Parent == null?Array.Empty <IEdmNavigationProperty>() : navigationItem.Parent.GetJoinPath();

            Expression?joinPropertyExpression = _expressionBuilder.JoinBuilder.GetJoinPropertyExpression(outerParameter, joinPath);

            if (joinPropertyExpression == null)
            {
                throw new InvalidOperationException("Outer source not found");
            }

            MethodCallExpression subquery = CreateWhereExpression(joinPropertyExpression, inner, navigationProperty);

            MethodInfo methodInfo = OeMethodInfoHelper.GetCountMethodInfo(innerType);

            subquery = Expression.Call(methodInfo, subquery);

            List <Expression> expressions = new List <Expression>();

            if (OeExpressionHelper.IsTupleType(outerParameter.Type))
            {
                expressions.AddRange(OeExpressionHelper.GetPropertyExpressions(outerParameter));
            }
            else
            {
                expressions.Add(outerParameter);
            }
            expressions.Add(OeExpressionHelper.CreateTupleExpression(new[] { subquery }));
            NewExpression newTuple = OeExpressionHelper.CreateTupleExpression(expressions);

            methodInfo = OeMethodInfoHelper.GetSelectMethodInfo(outerType, newTuple.Type);
            return(Expression.Call(methodInfo, outer, Expression.Lambda(newTuple, outerParameter)));
        }
Example #14
0
        private MethodCallExpression ApplyCompute(Expression source, ComputeTransformationNode transformation)
        {
            var expressions = new List <Expression>();

            Type sourceType = OeExpressionHelper.GetCollectionItemType(source.Type);
            ParameterExpression sourceParameter = Expression.Parameter(sourceType);

            if (_aggProperties.Count > 0)
            {
                var callExpression = (MethodCallExpression)source;
                source = callExpression.Arguments[0];
                var aggLambda = (LambdaExpression)callExpression.Arguments[1];
                expressions.AddRange(((NewExpression)aggLambda.Body).Arguments);

                sourceType      = OeExpressionHelper.GetCollectionItemType(source.Type);
                sourceParameter = aggLambda.Parameters[0];
            }

            OeQueryNodeVisitor visitor = CreateVisitor(sourceParameter);

            if (_aggProperties.Count > 0)
            {
                visitor.TuplePropertyByAliasName = new ComputeAliasNameResolver(_aggProperties, expressions).GetTuplePropertyByAliasName;
            }

            foreach (ComputeExpression computeExpression in transformation.Expressions)
            {
                Expression expression = visitor.TranslateNode(computeExpression.Expression);
                expressions.Add(expression);

                _aggProperties.Add(CreateEdmProperty(visitor.EdmModel, expression.Type, computeExpression.Alias, false));
            }

            NewExpression    newExpression    = OeExpressionHelper.CreateTupleExpression(expressions);
            MethodInfo       selectMethodInfo = OeMethodInfoHelper.GetSelectMethodInfo(sourceParameter.Type, newExpression.Type);
            LambdaExpression lambda           = Expression.Lambda(newExpression, sourceParameter);

            return(Expression.Call(selectMethodInfo, source, lambda));
        }
        private static Expression SelectStructuralProperties(Expression source, OeNavigationSelectItem root)
        {
            if (!root.HasNavigationItems())
            {
                return(source);
            }

            ParameterExpression parameter          = Expression.Parameter(OeExpressionHelper.GetCollectionItemType(source.Type));
            IReadOnlyList <MemberExpression> joins = OeExpressionHelper.GetPropertyExpressions(parameter);
            var newJoins = new Expression[joins.Count];

            List <OeNavigationSelectItem> navigationItems = FlattenNavigationItems(root, false);
            bool isNavigationNullable = false;

            for (int i = 0; i < navigationItems.Count; i++)
            {
                newJoins[i]           = joins[i];
                isNavigationNullable |= i > 0 && navigationItems[i].EdmProperty.Type.IsNullable;
                if (!navigationItems[i].AllSelected)
                {
                    IReadOnlyList <OeStructuralSelectItem> structuralItems = navigationItems[i].GetStructuralItemsWithNotSelected();
                    if (structuralItems.Count > 0)
                    {
                        var properties = new Expression[structuralItems.Count];
                        for (int j = 0; j < structuralItems.Count; j++)
                        {
                            if (structuralItems[j].EdmProperty is ComputeProperty computeProperty)
                            {
                                properties[j] = new ReplaceParameterVisitor(joins[i]).Visit(computeProperty.Expression);
                            }
                            else
                            {
                                PropertyInfo property = joins[i].Type.GetPropertyIgnoreCase(structuralItems[j].EdmProperty);
                                properties[j] = Expression.Property(joins[i], property);
                            }
                        }
                        Expression newTupleExpression = OeExpressionHelper.CreateTupleExpression(properties);

                        if (isNavigationNullable)
                        {
                            UnaryExpression nullConstant = Expression.Convert(OeConstantToVariableVisitor.NullConstantExpression, newTupleExpression.Type);
                            newTupleExpression = Expression.Condition(Expression.Equal(joins[i], OeConstantToVariableVisitor.NullConstantExpression), nullConstant, newTupleExpression);
                        }
                        newJoins[i] = newTupleExpression;
                    }
                }
            }

            NewExpression    newSelectorBody  = OeExpressionHelper.CreateTupleExpression(newJoins);
            MethodInfo       selectMethodInfo = OeMethodInfoHelper.GetSelectMethodInfo(parameter.Type, newSelectorBody.Type);
            LambdaExpression newSelector      = Expression.Lambda(newSelectorBody, parameter);

            //Quirk EF Core 2.1.1 bug Take/Skip must be last in expression tree
            var skipTakeExpressions = new List <MethodCallExpression>();

            while (source is MethodCallExpression callExpression && (callExpression.Method.Name == nameof(Enumerable.Skip) || callExpression.Method.Name == nameof(Enumerable.Take)))
            {
                skipTakeExpressions.Add(callExpression);
                source = callExpression.Arguments[0];
            }

            source = Expression.Call(selectMethodInfo, source, newSelector);

            for (int i = skipTakeExpressions.Count - 1; i >= 0; i--)
            {
                MethodInfo skipTakeMethodInfo = skipTakeExpressions[i].Method.GetGenericMethodDefinition().MakeGenericMethod(newSelector.ReturnType);
                source = Expression.Call(skipTakeMethodInfo, source, skipTakeExpressions[i].Arguments[1]);
            }

            return(source);
        }
Example #16
0
        private static MethodCallExpression AggCallExpression(AggregationMethod aggMethod, ParameterExpression sourceParameter, LambdaExpression lambda)
        {
            String methodName;

            switch (aggMethod)
            {
            case AggregationMethod.Average:
                methodName = nameof(Enumerable.Average);
                break;

            case AggregationMethod.CountDistinct:
                return(CountDistinctExpression(sourceParameter, lambda));

            case AggregationMethod.Max:
                methodName = nameof(Enumerable.Max);
                break;

            case AggregationMethod.Min:
                methodName = nameof(Enumerable.Min);
                break;

            case AggregationMethod.Sum:
                methodName = nameof(Enumerable.Sum);
                break;

            case AggregationMethod.VirtualPropertyCount:
                return(CountExpression(sourceParameter));

            default:
                throw new NotSupportedException();
            }

            MethodInfo closeMethod;
            MethodInfo openMethod = OeMethodInfoHelper.GetAggMethodInfo(methodName, lambda.ReturnType);

            if (openMethod == null)
            {
                Func <IEnumerable <Object>, Func <Object, Object>, Object> aggFunc;
                switch (aggMethod)
                {
                case AggregationMethod.Max:
                    aggFunc = Enumerable.Max;
                    break;

                case AggregationMethod.Min:
                    aggFunc = Enumerable.Min;
                    break;

                default:
                    throw new InvalidOperationException($"Enumerable.{methodName} not found");;
                }
                openMethod  = aggFunc.GetMethodInfo().GetGenericMethodDefinition();
                closeMethod = openMethod.MakeGenericMethod(lambda.Parameters[0].Type, lambda.ReturnType);
            }
            else
            {
                closeMethod = openMethod.MakeGenericMethod(lambda.Parameters[0].Type);
            }

            return(Expression.Call(closeMethod, sourceParameter, lambda));
        }