예제 #1
0
        public virtual IEnumerable <T> ExecuteSubQuery <T>(LambdaExpression query, IDataReader dataReader)
        {
            var projection = (SqlProjectionExpression)query.Body;

            var expectedSelector = "GROUPBYCOLUMNS-" + projection.Select.Alias;

            projection = (SqlProjectionExpression)ExpressionReplacer.Replace(projection, c =>
            {
                if (query.Parameters[0] == c)
                {
                    return(Expression.Constant(this));
                }

                var column = c as SqlColumnExpression;

                if (column != null && column.SelectAlias.StartsWith(expectedSelector))
                {
                    var sqlDataTypeProvider = this.SqlDatabaseContext.SqlDataTypeProvider.GetSqlDataType(column.Type);

                    var parameter = Expression.Parameter(typeof(IDataReader));
                    var func      = Expression.Lambda <Func <IDataReader, object> >(Expression.Convert(sqlDataTypeProvider.GetReadExpression(parameter, dataReader.GetOrdinal(column.Name)), typeof(object)), parameter).Compile();

                    var value = func(dataReader);

                    return(Expression.Constant(value, column.Type));
                }

                return(null);
            });

            projection = (SqlProjectionExpression)SqlQueryProvider.Optimize(projection, this.SqlDatabaseContext.SqlDataTypeProvider.GetTypeForEnums(), true);

            return(this.provider.CreateQuery <T>(projection));
        }
예제 #2
0
        protected Expression RewriteExplicitJoinProjection(MethodCallExpression methodCallExpression)
        {
            var outer            = this.Visit(methodCallExpression.Arguments[0]);
            var inner            = this.Visit(methodCallExpression.Arguments[1]);
            var outerKeySelector = methodCallExpression.Arguments[2].StripQuotes();
            var innerKeySelector = methodCallExpression.Arguments[3].StripQuotes();
            var resultSelector   = methodCallExpression.Arguments[4].StripQuotes();

            var originalOuterKeyParam = resultSelector.StripQuotes().Parameters[0];
            var originalInnerKeyParam = resultSelector.StripQuotes().Parameters[1];

            var outerKey    = Expression.Parameter(outerKeySelector.Parameters[0].Type);
            var innerKey    = Expression.Parameter(innerKeySelector.Parameters[0].Type);
            var resultValue = Expression.Parameter(typeof(ExpandedJoinSelectKey <,>).MakeGenericType(outerKey.Type, innerKey.Type));

            var newResultSelector = Expression.Lambda(Expression.MemberInit(resultValue.Type.CreateNewExpression(), Expression.Bind(resultValue.Type.GetProperty("Outer"), outerKey), Expression.Bind(resultValue.Type.GetProperty("Inner"), innerKey)), outerKey, innerKey);

            var newJoin = Expression.Call(null, MethodInfoFastRef.QueryableJoinMethod.MakeGenericMethod(outer.Type.GetSequenceElementType(), inner.Type.GetSequenceElementType(), outerKeySelector.ReturnType, newResultSelector.ReturnType), outer, inner, outerKeySelector, innerKeySelector, newResultSelector);

            var selectorParameter   = Expression.Parameter(resultValue.Type);
            var selectProjectorBody = ExpressionReplacer.Replace(resultSelector.Body, originalOuterKeyParam, Expression.Property(selectorParameter, "Outer"));

            selectProjectorBody = ExpressionReplacer.Replace(selectProjectorBody, originalInnerKeyParam, Expression.Property(selectorParameter, "Inner"));

            var selectProjector = Expression.Lambda(selectProjectorBody, selectorParameter);

            var select = Expression.Call(null, MethodInfoFastRef.QueryableSelectMethod.MakeGenericMethod(selectorParameter.Type, selectProjector.ReturnType), newJoin, selectProjector);

            return(select);
        }
예제 #3
0
        private static MethodCallExpression MakeJoinCallExpression(int index, Expression left, Expression right, PropertyPath targetPath, Dictionary <PropertyPath, int> indexByPath, Dictionary <PropertyPath, Expression> rootExpressionsByPath, Expression sourceParameterExpression)
        {
            Expression leftObject;

            var leftElementType  = left.Type.GetGenericArguments()[0];
            var rightElementType = right.Type.GetGenericArguments()[0];

            var rootPath = targetPath.PathWithoutLast();
            var leftSelectorParameter = Expression.Parameter(leftElementType);

            if (index == 1 && rootExpressionsByPath.ContainsKey(rootPath))
            {
                leftObject = rootExpressionsByPath[rootPath];

                leftObject = ExpressionReplacer.Replace(leftObject, c =>
                {
                    if (c == sourceParameterExpression)
                    {
                        return(leftSelectorParameter);
                    }

                    return(null);
                });
            }
            else
            {
                leftObject = CreateExpressionForPath(index - 1, rootPath, leftSelectorParameter, indexByPath);

                if (rootExpressionsByPath.ContainsKey(rootPath))
                {
                    foreach (var property in rootPath)
                    {
                        leftObject = Expression.Property(leftObject, property.Name);
                    }
                }
            }

            var leftSelector = Expression.Lambda(Expression.Property(leftObject, targetPath.Last().Name), leftSelectorParameter);

            var rightSelectorParameter = Expression.Parameter(rightElementType);
            var rightSelector          = Expression.Lambda(rightSelectorParameter, rightSelectorParameter);

            var projector = MakeJoinProjector(leftElementType, rightElementType);

            right = Expression.Call(null, MethodInfoFastRef.QueryableDefaultIfEmptyMethod.MakeGenericMethod(rightElementType), right);

            var method = MethodInfoFastRef.QueryableJoinMethod.MakeGenericMethod(leftElementType, rightElementType, targetPath.Last().GetMemberReturnType(), projector.ReturnType);

            return(Expression.Call(null, method, left, right, Expression.Quote(leftSelector), Expression.Quote(rightSelector), Expression.Quote(projector)));
        }
예제 #4
0
        protected Expression RewriteBasicProjection(MethodCallExpression methodCallExpression, bool forSelector)
        {
            Expression[] originalSelectors;
            var          originalSource = methodCallExpression.Arguments[0];
            var          source         = this.Visit(originalSource);
            var          sourceType     = source.Type.GetGenericArguments()[0];
            var          originalPredicateOrSelector = methodCallExpression.Arguments[1];

            if (methodCallExpression.Arguments.Count == 2)
            {
                originalSelectors = new[] { originalPredicateOrSelector };
            }
            else
            {
                originalSelectors = new[] { originalPredicateOrSelector, methodCallExpression.Arguments[2] };
            }

            var sourceParameterExpression = (originalPredicateOrSelector.StripQuotes()).Parameters[0];
            var result = ReferencedRelatedObjectPropertyGatherer.Gather(this.model, originalSelectors, sourceParameterExpression, forSelector);
            var memberAccessExpressionsNeedingJoins = result.ReferencedRelatedObjectByPath;
            var currentRootExpressionsByPath        = result.RootExpressionsByPath;

            var predicateOrSelectors       = result.ReducedExpressions;
            var predicateOrSelectorLambdas = predicateOrSelectors.Select(c => c.StripQuotes()).ToArray();

            if (memberAccessExpressionsNeedingJoins.Count > 0)
            {
                var replacementExpressionForPropertyPath = new Dictionary <PropertyPath, Expression>(PropertyPathEqualityComparer.Default);

                var referencedObjectPaths = memberAccessExpressionsNeedingJoins
                                            .OrderBy(c => c.Key.Length)
                                            .Select(c => c.Value)
                                            .ToList();

                var types = referencedObjectPaths
                            .Select(c => c.FullAccessPropertyPath.Last.PropertyType)
                            .ToList();

                var finalTupleType = CreateFinalTupleType(sourceType, types);
                var replacementExpressionsByPropertyPathForSelector = new Dictionary <PropertyPath, Expression>(PropertyPathEqualityComparer.Default);
                var parameter = Expression.Parameter(finalTupleType);

                var i           = 1;
                var indexByPath = new Dictionary <PropertyPath, int>(PropertyPathEqualityComparer.Default);

                foreach (var value in referencedObjectPaths)
                {
                    indexByPath[value.FullAccessPropertyPath] = i++;
                }

                indexByPath[PropertyPath.Empty] = 0;

                foreach (var x in currentRootExpressionsByPath)
                {
                    indexByPath[x.Key] = 0;
                }

                foreach (var path in referencedObjectPaths.Select(c => c.FullAccessPropertyPath))
                {
                    var replacement = CreateExpressionForPath(referencedObjectPaths.Count, path, parameter, indexByPath);

                    replacementExpressionsByPropertyPathForSelector[path] = replacement;
                }

                replacementExpressionsByPropertyPathForSelector[PropertyPath.Empty] = CreateExpressionForPath(referencedObjectPaths.Count, PropertyPath.Empty, parameter, indexByPath);

                foreach (var value in replacementExpressionsByPropertyPathForSelector)
                {
                    replacementExpressionForPropertyPath[value.Key] = value.Value;
                }

                var propertyPathsByOriginalExpression = referencedObjectPaths
                                                        .SelectMany(d => d.TargetExpressions.Select(e => new { PropertyPath = d.FullAccessPropertyPath, Expression = e }))
                                                        .ToDictionary(c => c.Expression, c => c.PropertyPath);

                foreach (var lambda in predicateOrSelectorLambdas)
                {
                    propertyPathsByOriginalExpression[lambda.Parameters[0]] = PropertyPath.Empty;
                }

                var replacementExpressions = propertyPathsByOriginalExpression
                                             .ToDictionary(c => c.Key, c => replacementExpressionsByPropertyPathForSelector[c.Value]);

                var index       = 1;
                var currentLeft = source;

                foreach (var referencedObjectPath in referencedObjectPaths)
                {
                    var property = referencedObjectPath.FullAccessPropertyPath[referencedObjectPath.FullAccessPropertyPath.Length - 1];
                    var right    = Expression.Constant(this.model.GetDataAccessObjects(property.PropertyType), typeof(DataAccessObjects <>).MakeGenericType(property.PropertyType));

                    var join = MakeJoinCallExpression(index, currentLeft, right, referencedObjectPath.FullAccessPropertyPath, indexByPath, currentRootExpressionsByPath, sourceParameterExpression);

                    currentLeft = join;
                    index++;
                }

                Func <Expression, bool, Expression> replace = null;

                replace = (e, b) => ExpressionReplacer.Replace(e, c =>
                {
                    Expression value;

                    if (forSelector && b)
                    {
                        if (result.IncludedPropertyInfoByExpression.ContainsKey(c))
                        {
                            var x = replace(c, false);
                            var y = result.IncludedPropertyInfoByExpression[c];

                            var newList = y.Select(includedPropertyInfo => new IncludedPropertyInfo
                            {
                                RootExpression         = x,
                                FullAccessPropertyPath = includedPropertyInfo.FullAccessPropertyPath,
                                IncludedPropertyPath   = includedPropertyInfo.IncludedPropertyPath
                            }).ToList();

                            this.includedPropertyInfos[x] = newList;

                            return(x);
                        }
                    }

                    if (replacementExpressions.TryGetValue(c, out value))
                    {
                        return(value);
                    }

                    return(null);
                });

                var newPredicatorOrSelectorBodies = predicateOrSelectorLambdas.Select(c => replace(c.Body, true)).ToArray();
                var newPredicateOrSelectors       = newPredicatorOrSelectorBodies.Select(c => Expression.Lambda(c, parameter)).ToArray();

                MethodInfo           newMethod;
                MethodCallExpression newCall;
                var newParameterType = newPredicateOrSelectors[0].Parameters[0].Type;

                if (methodCallExpression.Method.Name.StartsWith("Select") ||
                    methodCallExpression.Method.Name.StartsWith("Where") ||
                    methodCallExpression.Method.Name.EqualsIgnoreCase("OrderBy"))
                {
                    if (methodCallExpression.Method.Name.StartsWith("Select"))
                    {
                        var projectionResultType = newPredicateOrSelectors[0].ReturnType;

                        newMethod = methodCallExpression.Method.GetGenericMethodDefinition().MakeGenericMethod(newParameterType, projectionResultType);

                        newCall = Expression.Call(null, newMethod, new[]
                        {
                            currentLeft,
                            newPredicateOrSelectors[0]
                        });
                    }
                    else if (methodCallExpression.Method.Name.StartsWith("Where"))
                    {
                        newMethod = methodCallExpression.Method.GetGenericMethodDefinition().MakeGenericMethod(newParameterType);

                        newCall = Expression.Call(null, newMethod, new[]
                        {
                            currentLeft,
                            newPredicateOrSelectors[0]
                        });
                    }
                    else if (methodCallExpression.Method.Name.StartsWith("OrderBy"))
                    {
                        var keyType = newPredicateOrSelectors[0].ReturnType;

                        newMethod = methodCallExpression.Method.GetGenericMethodDefinition().MakeGenericMethod(newParameterType, keyType);

                        newCall = Expression.Call(null, newMethod, new[]
                        {
                            currentLeft,
                            newPredicateOrSelectors[0]
                        });
                    }
                    else
                    {
                        throw new InvalidOperationException();
                    }

                    if (newCall.Method.ReturnType.GetGenericArguments()[0].IsGenericType &&
                        newCall.Method.ReturnType.GetGenericArguments()[0].GetGenericTypeDefinition() == typeof(LeftRightJoinInfo <,>))
                    {
                        var selectParameter = Expression.Parameter(newCall.Method.ReturnType.GetGenericArguments()[0]);
                        var selectBody      = CreateExpressionForPath(referencedObjectPaths.Count, PropertyPath.Empty, selectParameter, indexByPath);
                        var selectCall      = Expression.Lambda(selectBody, selectParameter);

                        var selectMethod = MethodInfoFastRef.QueryableSelectMethod.MakeGenericMethod
                                           (
                            selectParameter.Type,
                            selectCall.ReturnType
                                           );

                        newCall = Expression.Call(null, selectMethod, new Expression[] { newCall, selectCall });
                    }

                    this.replacementExpressionForPropertyPathsByJoin.Add(new Pair <Expression, Dictionary <PropertyPath, Expression> >(newCall, replacementExpressionForPropertyPath));
                }
                else if (methodCallExpression.Method.Name == ("GroupBy"))
                {
                    var keyType     = newPredicateOrSelectors[0].ReturnType;
                    var elementType = methodCallExpression.Method.ReturnType.GetGenericArguments()[0].GetGenericArguments()[1];

                    newMethod = methodCallExpression.Method
                                .DeclaringType
                                .GetMethods().Single(c => c.IsGenericMethod &&
                                                     c.GetGenericArguments().Length == 3 &&
                                                     c.GetParameters().Length == 3 &&
                                                     c.GetParameters()[1].ParameterType.IsGenericType &&
                                                     c.GetParameters()[2].ParameterType.IsGenericType &&
                                                     c.GetParameters()[1].ParameterType.GetGenericTypeDefinition() == typeof(Expression <>) &&
                                                     c.GetParameters()[2].ParameterType.GetGenericTypeDefinition() == typeof(Expression <>) &&
                                                     c.GetParameters()[1].ParameterType.GetGenericArguments()[0].IsGenericType &&
                                                     c.GetParameters()[2].ParameterType.GetGenericArguments()[0].IsGenericType &&
                                                     c.GetParameters()[1].ParameterType.GetGenericArguments()[0].GetGenericTypeDefinition() == typeof(Func <,>) &&
                                                     c.GetParameters()[2].ParameterType.GetGenericArguments()[0].GetGenericTypeDefinition() == typeof(Func <,>))
                                .MakeGenericMethod(newParameterType, keyType, elementType);

                    var elementSelectorParameter = Expression.Parameter(newParameterType);
                    var elementSelectorBody      = CreateExpressionForPath(referencedObjectPaths.Count, PropertyPath.Empty, elementSelectorParameter, indexByPath);
                    var elementSelector          = Expression.Lambda(elementSelectorBody, elementSelectorParameter);

                    newCall = Expression.Call(null, newMethod, new []
                    {
                        currentLeft,
                        newPredicateOrSelectors[0],
                        elementSelector
                    });
                }
                else
                {
                    throw new InvalidOperationException("Method: " + methodCallExpression.Method);
                }

                this.replacementExpressionForPropertyPathsByJoin.Add(new Pair <Expression, Dictionary <PropertyPath, Expression> >(newCall, replacementExpressionForPropertyPath));

                return(newCall);
            }
            else
            {
                if (source == originalSource &&
                    predicateOrSelectors.SequenceEqual(originalSelectors, ObjectReferenceIdentityEqualityComparer <Expression> .Default))
                {
                    return(methodCallExpression);
                }
                else
                {
                    return(Expression.Call
                           (
                               methodCallExpression.Object,
                               methodCallExpression.Method,
                               predicateOrSelectors.Prepend(source).ToArray()
                           ));
                }
            }
        }