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)); }
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); }
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))); }
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() )); } } }