private MethodCallExpression CreateSelectExpression(Expression source)
        {
            if (_rootNavigationItem.HasNavigationItems())
            {
                return((MethodCallExpression)source);
            }

            if (_rootNavigationItem.AllSelected)
            {
                return((MethodCallExpression)source);
            }

            ParameterExpression parameter = _joinBuilder.Visitor.Parameter;
            IReadOnlyList <OeStructuralSelectItem> structuralItems = _rootNavigationItem.GetStructuralItemsWithNotSelected();
            var expressions = new Expression[structuralItems.Count];

            for (int i = 0; i < expressions.Length; i++)
            {
                if (structuralItems[i].EdmProperty is ComputeProperty computeProperty)
                {
                    expressions[i] = computeProperty.Expression;
                }
                else
                {
                    PropertyInfo clrProperty = parameter.Type.GetPropertyIgnoreCase(structuralItems[i].EdmProperty);
                    expressions[i] = Expression.MakeMemberAccess(parameter, clrProperty);
                }
            }
            NewExpression newTupleExpression = OeExpressionHelper.CreateTupleExpression(expressions);

            LambdaExpression lambda           = Expression.Lambda(newTupleExpression, parameter);
            MethodInfo       selectMethodInfo = OeMethodInfoHelper.GetSelectMethodInfo(parameter.Type, newTupleExpression.Type);

            return(Expression.Call(selectMethodInfo, source, lambda));
        }
Example #2
0
        private MethodCallExpression CreateSelectExpression(Expression source, OeJoinBuilder joinBuilder)
        {
            if (_navigationItem.HasNavigationItems)
            {
                return((MethodCallExpression)source);
            }

            if (_navigationItem.SelectItems.Count == 0)
            {
                return((MethodCallExpression)source);
            }

            var expressions = new List <Expression>(_navigationItem.SelectItems.Count);

            for (int i = 0; i < _navigationItem.SelectItems.Count; i++)
            {
                IEdmProperty edmProperty = _navigationItem.SelectItems[i].EdmProperty;
                PropertyInfo clrProperty = OeEdmClrHelper.GetPropertyIgnoreCase(_visitor.Parameter.Type, edmProperty);
                expressions.Add(Expression.MakeMemberAccess(_visitor.Parameter, clrProperty));
            }
            NewExpression newTupleExpression = OeExpressionHelper.CreateTupleExpression(expressions);

            LambdaExpression lambda           = Expression.Lambda(newTupleExpression, _visitor.Parameter);
            MethodInfo       selectMethodInfo = OeMethodInfoHelper.GetSelectMethodInfo(_visitor.Parameter.Type, newTupleExpression.Type);

            return(Expression.Call(selectMethodInfo, source, lambda));
        }
Example #3
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));
        }
Example #4
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 #5
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));
        }
Example #6
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 #8
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);
        }