static Expression MakeSubQueryExpression(MappingSchema mappingSchema, Expression sequence, ParameterExpression param, Expression expr1, Expression expr2) { var filterLambda = Expression.Lambda(ExpressionBuilder.Equal(mappingSchema, expr1, expr2), param); return(TypeHelper.MakeMethodCall(Methods.Enumerable.Where, sequence, filterLambda)); }
public Expression GetGroupJoin(GroupJoinContext context) { // Convert outer condition. // var outerParam = Expression.Parameter(context._outerKeyLambda.Body.Type, "o"); var outerKey = context._outerKeyLambda.GetBody(context.Lambda.Parameters[0]); outerKey = context.Builder.BuildExpression(context, outerKey, false); // Convert inner condition. // var parameters = context.Builder.CurrentSqlParameters .Select((p,i) => new { p, i }) .ToDictionary(_ => _.p.Expression, _ => _.i); var paramArray = Expression.Parameter(typeof(object[]), "ps"); var innerKey = context._innerKeyLambda.Body.Transform(e => { int idx; if (parameters.TryGetValue(e, out idx)) { return Expression.Convert( Expression.ArrayIndex(paramArray, Expression.Constant(idx)), e.Type); } return e; }); // Item reader. // var expr = Expression.Call( null, MemberHelper.MethodOf(() => Queryable.Where(null, (Expression<Func<TElement,bool>>)null)), context._innerExpression, Expression.Lambda<Func<TElement,bool>>( ExpressionBuilder.Equal(context.Builder.MappingSchema, innerKey, outerParam), new[] { context._innerKeyLambda.Parameters[0] })); var lambda = Expression.Lambda<Func<IDataContext,TKey,object[],IQueryable<TElement>>>( Expression.Convert(expr, typeof(IQueryable<TElement>)), Expression.Parameter(typeof(IDataContext), "ctx"), outerParam, paramArray); var itemReader = CompiledQuery.Compile(lambda); return Expression.Call( null, MemberHelper.MethodOf(() => GetGrouping(null, null, default(TKey), null)), new[] { ExpressionBuilder.QueryRunnerParam, Expression.Constant(context.Builder.CurrentSqlParameters), outerKey, Expression.Constant(itemReader), }); }
public Expression GetContext(MappingSchema mappingSchema, Expression sequence, ParameterExpression param, Expression expr1, Expression expr2) { // ReSharper disable AssignNullToNotNullAttribute //ReflectionHelper.Expressor<object>.MethodExpressor(_ => Queryable.Where(null, (Expression<Func<T,bool>>)null)), var mi = MemberHelper.MethodOf(() => Enumerable.Where(null, (Func <T, bool>)null)); // ReSharper restore AssignNullToNotNullAttribute var arg2 = Expression.Lambda <Func <T, bool> >(ExpressionBuilder.Equal(mappingSchema, expr1, expr2), new[] { param }); return(Expression.Call(null, mi, sequence, arg2)); }
public Expression GetGroupJoinCall(GroupJoinContext context) { var expr = Expression.Call( null, MemberHelper.MethodOf(() => Queryable.Where(null, (Expression<Func<T,bool>>)null)), context._innerExpression, Expression.Lambda<Func<T,bool>>( ExpressionBuilder.Equal( context.Builder.MappingSchema, context._innerKeyLambda.Body.Unwrap(), context._outerKeyLambda.GetBody(context.Lambda.Parameters[0])), new[] { context._innerKeyLambda.Parameters[0] })); return expr; }
public override ISqlExpression GetSubQuery(IBuildContext context) { if (_subQuerySql == null) { var args = _methodCall.Method.GetGenericArguments(); var param = Expression.Parameter(args[0], "param"); var expr = _methodCall.Arguments[1]; var condition = Expression.Lambda(ExpressionBuilder.Equal(Builder.MappingSchema, param, expr), param); IBuildContext ctx = new ExpressionContext(Parent, Sequence, condition); ctx = Builder.GetContext(ctx, expr) ?? ctx; Builder.ReplaceParent(ctx, this); SelectQuery.Condition cond; if (Sequence.SelectQuery != SelectQuery && (ctx.IsExpression(expr, 0, RequestFor.Field).Result || ctx.IsExpression(expr, 0, RequestFor.Expression).Result)) { Sequence.ConvertToIndex(null, 0, ConvertFlags.All); var ex = Builder.ConvertToSql(ctx, _methodCall.Arguments[1]); cond = new SelectQuery.Condition(false, new SelectQuery.Predicate.InSubQuery(ex, false, SelectQuery)); } else { var sequence = Builder.BuildWhere(Parent, Sequence, condition, true); cond = new SelectQuery.Condition(false, new SelectQuery.Predicate.FuncLike(SqlFunction.CreateExists(sequence.SelectQuery))); } _subQuerySql = new SelectQuery.SearchCondition(cond); } return(_subQuerySql); }
public Expression GetGrouping(GroupByContext context) { if (Configuration.Linq.GuardGrouping) { if (context._element.Lambda.Parameters.Count == 1 && context._element.Body == context._element.Lambda.Parameters[0]) { var ex = new LinqToDBException( "You should explicitly specify selected fields for server-side GroupBy() call or add AsEnumerable() call before GroupBy() to perform client-side grouping.\n" + "Set Configuration.Linq.GuardGrouping = false to disable this check." ) { HelpLink = "https://github.com/linq2db/linq2db/issues/365" }; throw ex; } } var parameters = context.Builder.CurrentSqlParameters .Select((p, i) => new { p, i }) .ToDictionary(_ => _.p.Expression, _ => _.i); var paramArray = Expression.Parameter(typeof(object[]), "ps"); var groupExpression = context._sequenceExpr.Transform(e => { int idx; if (parameters.TryGetValue(e, out idx)) { return (Expression.Convert( Expression.ArrayIndex(paramArray, Expression.Constant(idx)), e.Type)); } return(e); }); var keyParam = Expression.Parameter(typeof(TKey), "key"); // ReSharper disable AssignNullToNotNullAttribute var expr = Expression.Call( null, MemberHelper.MethodOf(() => Queryable.Where(null, (Expression <Func <TSource, bool> >)null)), groupExpression, Expression.Lambda <Func <TSource, bool> >( ExpressionBuilder.Equal(context.Builder.MappingSchema, context._key.Lambda.Body, keyParam), new[] { context._key.Lambda.Parameters[0] })); expr = Expression.Call( null, MemberHelper.MethodOf(() => Queryable.Select(null, (Expression <Func <TSource, TElement> >)null)), expr, context._element.Lambda); // ReSharper restore AssignNullToNotNullAttribute var lambda = Expression.Lambda <Func <IDataContext, TKey, object[], IQueryable <TElement> > >( Expression.Convert(expr, typeof(IQueryable <TElement>)), Expression.Parameter(typeof(IDataContext), "ctx"), keyParam, paramArray); var itemReader = CompiledQuery.Compile(lambda); var keyExpr = context._key.BuildExpression(null, 0, false); var dataReaderLocal = context.Builder.DataReaderLocal; if (!Configuration.AvoidSpecificDataProviderAPI && keyExpr.Find(e => e == dataReaderLocal) != null) { keyExpr = Expression.Block( new[] { context.Builder.DataReaderLocal }, new[] { Expression.Assign(dataReaderLocal, Expression.Convert(ExpressionBuilder.DataReaderParam, context.Builder.DataContext.DataReaderType)), keyExpr }); } var keyReader = Expression.Lambda <Func <IQueryRunner, IDataContext, IDataReader, Expression, object[], TKey> >( keyExpr, new [] { ExpressionBuilder.QueryRunnerParam, ExpressionBuilder.DataContextParam, ExpressionBuilder.DataReaderParam, ExpressionBuilder.ExpressionParam, ExpressionBuilder.ParametersParam }); return(Expression.Call( null, MemberHelper.MethodOf(() => GetGrouping(null, null, null, null, null, null, null, null)), new Expression[] { ExpressionBuilder.QueryRunnerParam, ExpressionBuilder.DataContextParam, ExpressionBuilder.DataReaderParam, Expression.Constant(context.Builder.CurrentSqlParameters), ExpressionBuilder.ExpressionParam, ExpressionBuilder.ParametersParam, Expression.Constant(keyReader.Compile()), Expression.Constant(itemReader) })); }
// Returns // (ParentType p) => dc.GetTable<ObjectType>().Where(...) // (ParentType p) => dc.GetTable<ObjectType>().Where(...).DefaultIfEmpty public static LambdaExpression CreateAssociationQueryLambda(ExpressionBuilder builder, AccessorMember onMember, AssociationDescriptor association, Type parentOriginalType, Type parentType, Type objectType, bool inline, bool enforceDefault, List <LoadWithInfo[]>?loadWith, out bool isLeft) { var dataContextConstant = Expression.Constant(builder.DataContext, builder.DataContext.GetType()); // We are trying to keep fast cache hit behaviour, so cache check should be added only if needed // bool shouldAddCacheCheck = false; bool cacheCheckAdded = false; LambdaExpression?definedQueryMethod = null; if (association.HasQueryMethod()) { // here we tell for Expression Comparer to compare optimized Association expressions // definedQueryMethod = (LambdaExpression)builder.AddQueryableMemberAccessors(onMember, builder.DataContext, (mi, dc) => { var queryLambda = association.GetQueryMethod(parentType, objectType) ?? throw new InvalidOperationException(); var optimizationContext = new ExpressionTreeOptimizationContext(dc); var optimizedExpr = optimizationContext.ExposeExpression(queryLambda); optimizedExpr = optimizationContext.ExpandQueryableMethods(optimizedExpr); optimizedExpr = optimizedExpr.OptimizeExpression() !; return(optimizedExpr); }); cacheCheckAdded = true; var parameterMatch = new Dictionary <ParameterExpression, Expression>(); if (onMember.Arguments == null) { if (definedQueryMethod.Parameters.Count > 1 && typeof(IDataContext).IsSameOrParentOf(definedQueryMethod.Parameters[1].Type)) { parameterMatch.Add(definedQueryMethod.Parameters[1], dataContextConstant); } } else { var definedCount = definedQueryMethod.Parameters.Count; var argumentsCount = onMember.Arguments.Count; var diff = definedCount - argumentsCount; for (int i = definedCount - 1; i >= diff; i--) { parameterMatch.Add(definedQueryMethod.Parameters[i], onMember.Arguments[i - diff]); } } var body = definedQueryMethod.Body.Transform(e => { if (e.NodeType == ExpressionType.Parameter && parameterMatch.TryGetValue((ParameterExpression)e, out var newExpression)) { return(newExpression); } return(e); }); definedQueryMethod = Expression.Lambda(body, definedQueryMethod.Parameters[0]); } var shouldAddDefaultIfEmpty = enforceDefault; if (definedQueryMethod == null) { var parentParam = Expression.Parameter(parentType, "parent"); var childParam = Expression.Parameter(objectType, association.AliasName); var parentAccessor = TypeAccessor.GetAccessor(parentType); var childAccessor = TypeAccessor.GetAccessor(objectType); Expression?predicate = null; for (var i = 0; i < association.ThisKey.Length; i++) { var parentName = association.ThisKey[i]; var parentMember = parentAccessor.Members.Find(m => m.MemberInfo.Name == parentName); if (parentMember == null) { throw new LinqException("Association key '{0}' not found for type '{1}.", parentName, parentType); } var childName = association.OtherKey[i]; var childMember = childAccessor.Members.Find(m => m.MemberInfo.Name == childName); if (childMember == null) { throw new LinqException("Association key '{0}' not found for type '{1}.", childName, objectType); } var current = ExpressionBuilder.Equal(builder.MappingSchema, Expression.MakeMemberAccess(parentParam, parentMember.MemberInfo), Expression.MakeMemberAccess(childParam, childMember.MemberInfo)); predicate = predicate == null ? current : Expression.AndAlso(predicate, current); } var expressionPredicate = association.GetPredicate(parentType, objectType); if (expressionPredicate != null) { shouldAddDefaultIfEmpty = true; shouldAddCacheCheck = true; var replacedBody = expressionPredicate.GetBody(parentParam, childParam); predicate = predicate == null ? replacedBody : Expression.AndAlso(predicate, replacedBody); } if (predicate == null) { throw new LinqException("Can not generate Association predicate"); } if (inline && !shouldAddDefaultIfEmpty) { var ed = builder.MappingSchema.GetEntityDescriptor(objectType); if (ed.QueryFilterFunc != null) { shouldAddDefaultIfEmpty = true; shouldAddCacheCheck = true; } } var queryParam = Expression.Call(Methods.LinqToDB.GetTable.MakeGenericMethod(objectType), dataContextConstant); var filterLambda = Expression.Lambda(predicate, childParam); Expression body = Expression.Call(Methods.Queryable.Where.MakeGenericMethod(objectType), queryParam, filterLambda); definedQueryMethod = Expression.Lambda(body, parentParam); } else { shouldAddDefaultIfEmpty = true; var bodyExpression = definedQueryMethod.Body.Unwrap(); if (bodyExpression.NodeType == ExpressionType.Call) { var mc = (MethodCallExpression)bodyExpression; if (mc.IsSameGenericMethod(Methods.Queryable.DefaultIfEmpty, Methods.Queryable.DefaultIfEmptyValue)) { shouldAddDefaultIfEmpty = false; } } } if (!cacheCheckAdded && shouldAddCacheCheck) { // here we tell for Expression Comparer to compare optimized Association expressions // var closureExpr = definedQueryMethod; definedQueryMethod = (LambdaExpression)builder.AddQueryableMemberAccessors(onMember, builder.DataContext, (mi, dc) => { var optimizationContext = new ExpressionTreeOptimizationContext(dc); var optimizedExpr = optimizationContext.ExposeExpression(closureExpr); optimizedExpr = optimizationContext.ExpandQueryableMethods(optimizedExpr); optimizedExpr = optimizedExpr.OptimizeExpression() !; return(optimizedExpr); }); } if (loadWith != null) { var associationLoadWith = GetLoadWith(loadWith)? .FirstOrDefault(li => li.Info.MemberInfo == association.MemberInfo); if (associationLoadWith != null && (associationLoadWith.Info.MemberFilter != null || associationLoadWith.Info.FilterFunc != null)) { var body = definedQueryMethod.Body.Unwrap(); var memberFilter = associationLoadWith.Info.MemberFilter; if (memberFilter != null) { var elementType = EagerLoading.GetEnumerableElementType(memberFilter.Parameters[0].Type, builder.MappingSchema); var filtered = Expression.Convert(body, typeof(IEnumerable <>).MakeGenericType(elementType)); var filterBody = memberFilter.GetBody(filtered); body = Expression.Call( Methods.Enumerable.AsQueryable.MakeGenericMethod(objectType), filterBody); } var loadWithFunc = associationLoadWith.Info.FilterFunc; if (loadWithFunc != null) { loadWithFunc = loadWithFunc.Unwrap(); if (loadWithFunc is LambdaExpression lambda) { body = lambda.GetBody(body); } else { var filterDelegate = loadWithFunc.EvaluateExpression <Delegate>() ?? throw new LinqException("Cannot convert filter function '{loadWithFunc}' to Delegate."); var arumentType = filterDelegate.GetType().GetGenericArguments()[0].GetGenericArguments()[0]; // check for fake argument q => q if (arumentType.IsSameOrParentOf(objectType)) { var query = ExpressionQueryImpl.CreateQuery(objectType, builder.DataContext, body); var filtered = (IQueryable)filterDelegate.DynamicInvoke(query) !; body = filtered.Expression; } } } definedQueryMethod = Expression.Lambda(body, definedQueryMethod.Parameters); } if (associationLoadWith?.NextLoadWith != null && associationLoadWith.NextLoadWith.Count > 0) { definedQueryMethod = (LambdaExpression)EnrichTablesWithLoadWith(builder.DataContext, definedQueryMethod, objectType, associationLoadWith.NextLoadWith, builder.MappingSchema); } } if (parentOriginalType != parentType) { // add discriminator filter var ed = builder.MappingSchema.GetEntityDescriptor(parentOriginalType); foreach (var inheritanceMapping in ed.InheritanceMapping) { if (inheritanceMapping.Type == parentType) { var objParam = Expression.Parameter(objectType, "o"); var filterLambda = Expression.Lambda(ExpressionBuilder.Equal(builder.MappingSchema, Expression.MakeMemberAccess(definedQueryMethod.Parameters[0], inheritanceMapping.Discriminator.MemberInfo), Expression.Constant(inheritanceMapping.Code)), objParam); var body = definedQueryMethod.Body.Unwrap(); body = Expression.Call(Methods.Queryable.Where.MakeGenericMethod(objectType), body, filterLambda); definedQueryMethod = Expression.Lambda(body, definedQueryMethod.Parameters); shouldAddDefaultIfEmpty = true; break; } } } if (inline && shouldAddDefaultIfEmpty) { var body = definedQueryMethod.Body.Unwrap(); body = Expression.Call(Methods.Queryable.DefaultIfEmpty.MakeGenericMethod(objectType), body); definedQueryMethod = Expression.Lambda(body, definedQueryMethod.Parameters); isLeft = true; } else { isLeft = false; } definedQueryMethod = (LambdaExpression)builder.ConvertExpressionTree(definedQueryMethod); definedQueryMethod = (LambdaExpression)builder.ConvertExpression(definedQueryMethod); definedQueryMethod = (LambdaExpression)definedQueryMethod.OptimizeExpression() !; return(definedQueryMethod); }
public Expression GetGrouping(GroupByContext context) { if (Configuration.Linq.GuardGrouping && !context._isGroupingGuardDisabled) { if (context.Element.Lambda.Parameters.Count == 1 && context.Element.Body == context.Element.Lambda.Parameters[0]) { var ex = new LinqToDBException( "You should explicitly specify selected fields for server-side GroupBy() call or add AsEnumerable() call before GroupBy() to perform client-side grouping.\n" + "Set Configuration.Linq.GuardGrouping = false to disable this check.\n" + "Additionally this guard exception can be disabled by extension GroupBy(...).DisableGuard().\n" + "NOTE! By disabling this guard you accept additional Database Connection(s) to the server for processing such requests." ) { HelpLink = "https://github.com/linq2db/linq2db/issues/365" }; throw ex; } } var parameters = context.Builder.CurrentSqlParameters .Select((p, i) => new { p, i }) .ToDictionary(_ => _.p.Expression, _ => _.i); var paramArray = Expression.Parameter(typeof(object[]), "ps"); var groupExpression = context._sequenceExpr.Transform(e => { if (parameters.TryGetValue(e, out var idx)) { return (Expression.Convert( Expression.ArrayIndex(paramArray, Expression.Constant(idx)), e.Type)); } return(e); }); var keyParam = Expression.Parameter(typeof(TKey), "key"); // ReSharper disable AssignNullToNotNullAttribute var expr = Expression.Call( null, MemberHelper.MethodOf(() => Queryable.Where(null, (Expression <Func <TSource, bool> >)null !)), groupExpression, Expression.Lambda <Func <TSource, bool> >( ExpressionBuilder.Equal(context.Builder.MappingSchema, context._key.Lambda.Body, keyParam), new[] { context._key.Lambda.Parameters[0] })); expr = Expression.Call( null, MemberHelper.MethodOf(() => Queryable.Select(null, (Expression <Func <TSource, TElement> >)null !)), expr, context.Element.Lambda); // ReSharper restore AssignNullToNotNullAttribute var lambda = Expression.Lambda <Func <IDataContext, TKey, object?[]?, IQueryable <TElement> > >( Expression.Convert(expr, typeof(IQueryable <TElement>)), Expression.Parameter(typeof(IDataContext), "ctx"), keyParam, paramArray); var itemReader = CompiledQuery.Compile(lambda); var keyExpr = context._key.BuildExpression(null, 0, false); var keyReader = Expression.Lambda <Func <IQueryRunner, IDataContext, IDataReader, Expression, object?[]?, TKey> >( keyExpr, new [] { ExpressionBuilder.QueryRunnerParam, ExpressionBuilder.DataContextParam, ExpressionBuilder.DataReaderParam, ExpressionBuilder.ExpressionParam, ExpressionBuilder.ParametersParam }); return(Expression.Call( null, MemberHelper.MethodOf(() => GetGrouping(null !, null !, null !, null !, null !, null !, null !, null !)), new Expression[] { ExpressionBuilder.QueryRunnerParam, ExpressionBuilder.DataContextParam, ExpressionBuilder.DataReaderParam, Expression.Constant(context.Builder.CurrentSqlParameters), ExpressionBuilder.ExpressionParam, ExpressionBuilder.ParametersParam, keyReader, Expression.Constant(itemReader) })); }
public Expression GetSubquery( ExpressionBuilder builder, AssociatedTableContext tableContext, ParameterExpression parentObject) { var lContext = Expression.Parameter(typeof(IDataContext), "ctx"); var lParent = Expression.Parameter(typeof(object), "parentObject"); Expression expression; var queryMethod = tableContext.Association.GetQueryMethod(parentObject.Type, typeof(T)); if (queryMethod != null) { var ownerParam = queryMethod.Parameters[0]; var dcParam = queryMethod.Parameters[1]; var ownerExpr = Expression.Convert(lParent, parentObject.Type); expression = queryMethod.Body.Transform(e => e == ownerParam ? ownerExpr : (e == dcParam ? lContext : e)); } else { var tableExpression = builder.DataContext.GetTable <T>(); var loadWith = tableContext.GetLoadWith(); if (loadWith != null) { foreach (var members in loadWith) { var pLoadWith = Expression.Parameter(typeof(T), "t"); var isPrevList = false; Expression obj = pLoadWith; foreach (var member in members) { if (isPrevList) { obj = new GetItemExpression(obj); } obj = Expression.MakeMemberAccess(obj, member); isPrevList = typeof(IEnumerable).IsSameOrParentOf(obj.Type); } tableExpression = tableExpression.LoadWith(Expression.Lambda <Func <T, object> >(obj, pLoadWith)); } } // Where var pWhere = Expression.Parameter(typeof(T), "t"); Expression expr = null; for (var i = 0; i < tableContext.Association.ThisKey.Length; i++) { var thisProp = Expression.PropertyOrField(Expression.Convert(lParent, parentObject.Type), tableContext.Association.ThisKey[i]); var otherProp = Expression.PropertyOrField(pWhere, tableContext.Association.OtherKey[i]); var ex = ExpressionBuilder.Equal(tableContext.Builder.MappingSchema, otherProp, thisProp); expr = expr == null ? ex : Expression.AndAlso(expr, ex); } var predicate = tableContext.Association.GetPredicate(parentObject.Type, typeof(T)); if (predicate != null) { var ownerParam = predicate.Parameters[0]; var childParam = predicate.Parameters[1]; var ownerExpr = Expression.Convert(lParent, parentObject.Type); var body = predicate.Body.Transform(e => e == ownerParam ? ownerExpr : (e == childParam ? pWhere : e)); expr = expr == null ? body : Expression.AndAlso(expr, body); } expression = tableExpression.Where(Expression.Lambda <Func <T, bool> >(expr, pWhere)).Expression; } var lambda = Expression.Lambda <Func <IDataContext, object, IEnumerable <T> > >(expression, lContext, lParent); var queryReader = CompiledQuery.Compile(lambda); expression = Expression.Call( null, MemberHelper.MethodOf(() => ExecuteSubQuery(null, null, null)), ExpressionBuilder.QueryRunnerParam, Expression.Convert(parentObject, typeof(object)), Expression.Constant(queryReader)); var memberType = tableContext.Association.MemberInfo.GetMemberType(); if (memberType == typeof(T[])) { return(Expression.Call(null, MemberHelper.MethodOf(() => Enumerable.ToArray <T>(null)), expression)); } if (memberType.IsSameOrParentOf(typeof(List <T>))) { return(Expression.Call(null, MemberHelper.MethodOf(() => Enumerable.ToList <T>(null)), expression)); } var ctor = memberType.GetConstructorEx(new[] { typeof(IEnumerable <T>) }); if (ctor != null) { return(Expression.New(ctor, expression)); } var l = builder.MappingSchema.GetConvertExpression(expression.Type, memberType, false, false); if (l != null) { return(l.GetBody(expression)); } throw new LinqToDBException($"Expected constructor '{memberType.Name}(IEnumerable<{tableContext.ObjectType}>)'"); }
public Expression GetGrouping(GroupByContext context) { var parameters = context.Builder.CurrentSqlParameters .Select((p, i) => new { p, i }) .ToDictionary(_ => _.p.Expression, _ => _.i); var paramArray = Expression.Parameter(typeof(object[]), "ps"); var groupExpression = context._sequenceExpr.Transform(e => { int idx; if (parameters.TryGetValue(e, out idx)) { return (Expression.Convert( Expression.ArrayIndex(paramArray, Expression.Constant(idx)), e.Type)); } return(e); }); var keyParam = Expression.Parameter(typeof(TKey), "key"); // ReSharper disable AssignNullToNotNullAttribute var expr = Expression.Call( null, MemberHelper.MethodOf(() => Queryable.Where(null, (Expression <Func <TSource, bool> >)null)), groupExpression, Expression.Lambda <Func <TSource, bool> >( ExpressionBuilder.Equal(context.Builder.MappingSchema, context._key.Lambda.Body, keyParam), new[] { context._key.Lambda.Parameters[0] })); expr = Expression.Call( null, MemberHelper.MethodOf(() => Queryable.Select(null, (Expression <Func <TSource, TElement> >)null)), expr, context._element.Lambda); // ReSharper restore AssignNullToNotNullAttribute var lambda = Expression.Lambda <Func <IDataContext, TKey, object[], IQueryable <TElement> > >( Expression.Convert(expr, typeof(IQueryable <TElement>)), Expression.Parameter(typeof(IDataContext), "ctx"), keyParam, paramArray); var itemReader = CompiledQuery.Compile(lambda); var keyExpr = context._key.BuildExpression(null, 0); var dataReaderLocal = context.Builder.DataReaderLocal; if (!Configuration.AvoidSpecificDataProviderAPI && keyExpr.Find(e => e == dataReaderLocal) != null) { keyExpr = Expression.Block( new[] { context.Builder.DataReaderLocal }, new[] { Expression.Assign(dataReaderLocal, Expression.Convert(ExpressionBuilder.DataReaderParam, context.Builder.DataContextInfo.DataContext.DataReaderType)), keyExpr }); } var keyReader = Expression.Lambda <Func <QueryContext, IDataContext, IDataReader, Expression, object[], TKey> >( keyExpr, new [] { ExpressionBuilder.ContextParam, ExpressionBuilder.DataContextParam, ExpressionBuilder.DataReaderParam, ExpressionBuilder.ExpressionParam, ExpressionBuilder.ParametersParam }); return(Expression.Call( null, MemberHelper.MethodOf(() => GetGrouping(null, null, null, null, null, null, null, null)), new Expression[] { ExpressionBuilder.ContextParam, ExpressionBuilder.DataContextParam, ExpressionBuilder.DataReaderParam, Expression.Constant(context.Builder.CurrentSqlParameters), ExpressionBuilder.ExpressionParam, ExpressionBuilder.ParametersParam, Expression.Constant(keyReader.Compile()), Expression.Constant(itemReader) })); }