0
|
1 using System;
|
|
2 using System.Collections;
|
|
3 using System.Collections.Generic;
|
|
4 using System.Data;
|
|
5 using System.Linq;
|
|
6 using System.Linq.Expressions;
|
|
7 using System.Reflection;
|
|
8
|
|
9 namespace BLToolkit.Data.Linq.Builder
|
|
10 {
|
|
11 using BLToolkit.Linq;
|
|
12 using Data.Sql;
|
|
13
|
|
14 class GroupByBuilder : MethodCallBuilder
|
|
15 {
|
|
16 #region Builder Methods
|
|
17
|
|
18 protected override bool CanBuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
|
|
19 {
|
|
20 if (!methodCall.IsQueryable("GroupBy"))
|
|
21 return false;
|
|
22
|
|
23 var body = ((LambdaExpression)methodCall.Arguments[1].Unwrap()).Body.Unwrap();
|
|
24
|
|
25 if (body.NodeType == ExpressionType.MemberInit)
|
|
26 {
|
|
27 var mi = (MemberInitExpression)body;
|
|
28 bool throwExpr;
|
|
29
|
|
30 if (mi.NewExpression.Arguments.Count > 0 || mi.Bindings.Count == 0)
|
|
31 throwExpr = true;
|
|
32 else
|
|
33 throwExpr = mi.Bindings.Any(b => b.BindingType != MemberBindingType.Assignment);
|
|
34
|
|
35 if (throwExpr)
|
|
36 throw new NotSupportedException(string.Format("Explicit construction of entity type '{0}' in group by is not allowed.", body.Type));
|
|
37 }
|
|
38
|
|
39 return (methodCall.Arguments[methodCall.Arguments.Count - 1].Unwrap().NodeType == ExpressionType.Lambda);
|
|
40 }
|
|
41
|
|
42 protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
|
|
43 {
|
|
44 var sequenceExpr = methodCall.Arguments[0];
|
|
45 var sequence = builder.BuildSequence(new BuildInfo(buildInfo, sequenceExpr));
|
|
46 var groupingType = methodCall.Type.GetGenericArguments()[0];
|
|
47 var keySelector = (LambdaExpression)methodCall.Arguments[1].Unwrap();
|
|
48 var elementSelector = (LambdaExpression)methodCall.Arguments[2].Unwrap();
|
|
49
|
|
50 if (methodCall.Arguments[0].NodeType == ExpressionType.Call)
|
|
51 {
|
|
52 var call = (MethodCallExpression)methodCall.Arguments[0];
|
|
53
|
|
54 if (call.Method.Name == "Select")
|
|
55 {
|
|
56 var type = ((LambdaExpression)call.Arguments[1].Unwrap()).Body.Type;
|
|
57
|
|
58 if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ExpressionBuilder.GroupSubQuery<,>))
|
|
59 {
|
|
60 sequence = new SubQueryContext(sequence);
|
|
61 }
|
|
62 }
|
|
63 }
|
|
64
|
|
65 var key = new KeyContext(buildInfo.Parent, keySelector, sequence);
|
|
66 var groupSql = builder.ConvertExpressions(key, keySelector.Body.Unwrap(), ConvertFlags.Key);
|
|
67
|
|
68 if (sequence.SqlQuery.Select.IsDistinct ||
|
|
69 sequence.SqlQuery.GroupBy.Items.Count > 0 ||
|
|
70 groupSql.Any(_ => !(_.Sql is SqlField || _.Sql is SqlQuery.Column)))
|
|
71 {
|
|
72 sequence = new SubQueryContext(sequence);
|
|
73 key = new KeyContext(buildInfo.Parent, keySelector, sequence);
|
|
74 groupSql = builder.ConvertExpressions(key, keySelector.Body.Unwrap(), ConvertFlags.Key);
|
|
75 }
|
|
76
|
|
77 //sequence.SqlQuery.GroupBy.Items.Clear();
|
|
78
|
|
79 foreach (var sql in groupSql)
|
|
80 sequence.SqlQuery.GroupBy.Expr(sql.Sql);
|
|
81
|
|
82 new QueryVisitor().Visit(sequence.SqlQuery.From, e =>
|
|
83 {
|
|
84 if (e.ElementType == QueryElementType.JoinedTable)
|
|
85 {
|
|
86 var jt = (SqlQuery.JoinedTable)e;
|
|
87 if (jt.JoinType == SqlQuery.JoinType.Inner)
|
|
88 jt.IsWeak = false;
|
|
89 }
|
|
90 });
|
|
91
|
|
92 var element = new SelectContext (buildInfo.Parent, elementSelector, sequence/*, key*/);
|
|
93 var groupBy = new GroupByContext(buildInfo.Parent, sequenceExpr, groupingType, sequence, key, element);
|
|
94
|
|
95 return groupBy;
|
|
96 }
|
|
97
|
|
98 protected override SequenceConvertInfo Convert(
|
|
99 ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo, ParameterExpression param)
|
|
100 {
|
|
101 return null;
|
|
102 }
|
|
103
|
|
104 #endregion
|
|
105
|
|
106 #region KeyContext
|
|
107
|
|
108 internal class KeyContext : SelectContext
|
|
109 {
|
|
110 public KeyContext(IBuildContext parent, LambdaExpression lambda, params IBuildContext[] sequences)
|
|
111 : base(parent, lambda, sequences)
|
|
112 {
|
|
113 }
|
|
114 }
|
|
115
|
|
116 #endregion
|
|
117
|
|
118 #region GroupByContext
|
|
119
|
|
120 internal class GroupByContext : SequenceContextBase
|
|
121 {
|
|
122 public GroupByContext(
|
|
123 IBuildContext parent,
|
|
124 Expression sequenceExpr,
|
|
125 Type groupingType,
|
|
126 IBuildContext sequence,
|
|
127 KeyContext key,
|
|
128 SelectContext element)
|
|
129 : base(parent, sequence, null)
|
|
130 {
|
|
131 _sequenceExpr = sequenceExpr;
|
|
132 _key = key;
|
|
133 _element = element;
|
|
134 _groupingType = groupingType;
|
|
135
|
|
136 key.Parent = this;
|
|
137 }
|
|
138
|
|
139 readonly Expression _sequenceExpr;
|
|
140 readonly KeyContext _key;
|
|
141 readonly SelectContext _element;
|
|
142 readonly Type _groupingType;
|
|
143
|
|
144 internal class Grouping<TKey,TElement> : IGrouping<TKey,TElement>
|
|
145 {
|
|
146 public Grouping(
|
|
147 TKey key,
|
|
148 QueryContext queryContext,
|
|
149 List<ParameterAccessor> parameters,
|
|
150 Func<IDataContext,TKey,object[],IQueryable<TElement>> itemReader)
|
|
151 {
|
|
152 Key = key;
|
|
153
|
|
154 _queryContext = queryContext;
|
|
155 _parameters = parameters;
|
|
156 _itemReader = itemReader;
|
|
157
|
|
158 if (Common.Configuration.Linq.PreloadGroups)
|
|
159 {
|
|
160 _items = GetItems();
|
|
161 }
|
|
162 }
|
|
163
|
|
164 private IList<TElement> _items;
|
|
165 readonly QueryContext _queryContext;
|
|
166 readonly List<ParameterAccessor> _parameters;
|
|
167 readonly Func<IDataContext,TKey,object[],IQueryable<TElement>> _itemReader;
|
|
168
|
|
169 public TKey Key { get; private set; }
|
|
170
|
|
171 List<TElement> GetItems()
|
|
172 {
|
|
173 var db = _queryContext.GetDataContext();
|
|
174
|
|
175 try
|
|
176 {
|
|
177 var ps = new object[_parameters.Count];
|
|
178
|
|
179 for (var i = 0; i < ps.Length; i++)
|
|
180 ps[i] = _parameters[i].Accessor(_queryContext.Expression, _queryContext.CompiledParameters);
|
|
181
|
|
182 return _itemReader(db.DataContextInfo.DataContext, Key, ps).ToList();
|
|
183 }
|
|
184 finally
|
|
185 {
|
|
186 _queryContext.ReleaseDataContext(db);
|
|
187 }
|
|
188 }
|
|
189
|
|
190 public IEnumerator<TElement> GetEnumerator()
|
|
191 {
|
|
192 if (_items == null)
|
|
193 _items = GetItems();
|
|
194
|
|
195 return _items.GetEnumerator();
|
|
196 }
|
|
197
|
|
198 IEnumerator IEnumerable.GetEnumerator()
|
|
199 {
|
|
200 return GetEnumerator();
|
|
201 }
|
|
202 }
|
|
203
|
|
204 interface IGroupByHelper
|
|
205 {
|
|
206 Expression GetGrouping(GroupByContext context);
|
|
207 }
|
|
208
|
|
209 class GroupByHelper<TKey,TElement,TSource> : IGroupByHelper
|
|
210 {
|
|
211 public Expression GetGrouping(GroupByContext context)
|
|
212 {
|
|
213 var parameters = context.Builder.CurrentSqlParameters
|
|
214 .Select((p,i) => new { p, i })
|
|
215 .ToDictionary(_ => _.p.Expression, _ => _.i);
|
|
216 var paramArray = Expression.Parameter(typeof(object[]), "ps");
|
|
217
|
|
218 var groupExpression = context._sequenceExpr.Convert(e =>
|
|
219 {
|
|
220 int idx;
|
|
221
|
|
222 if (parameters.TryGetValue(e, out idx))
|
|
223 {
|
|
224 return
|
|
225 Expression.Convert(
|
|
226 Expression.ArrayIndex(paramArray, Expression.Constant(idx)),
|
|
227 e.Type);
|
|
228 }
|
|
229
|
|
230 return e;
|
|
231 });
|
|
232
|
|
233 var keyParam = Expression.Parameter(typeof(TKey), "key");
|
|
234
|
|
235 // ReSharper disable AssignNullToNotNullAttribute
|
|
236
|
|
237 var expr = Expression.Call(
|
|
238 null,
|
|
239 ReflectionHelper.Expressor<object>.MethodExpressor(_ => Queryable.Where(null, (Expression<Func<TSource,bool>>)null)),
|
|
240 groupExpression,
|
|
241 Expression.Lambda<Func<TSource,bool>>(
|
|
242 Expression.Equal(context._key.Lambda.Body, keyParam),
|
|
243 new[] { context._key.Lambda.Parameters[0] }));
|
|
244
|
|
245 expr = Expression.Call(
|
|
246 null,
|
|
247 ReflectionHelper.Expressor<object>.MethodExpressor(_ => Queryable.Select(null, (Expression<Func<TSource,TElement>>)null)),
|
|
248 expr,
|
|
249 context._element.Lambda);
|
|
250
|
|
251 // ReSharper restore AssignNullToNotNullAttribute
|
|
252
|
|
253 var lambda = Expression.Lambda<Func<IDataContext,TKey,object[],IQueryable<TElement>>>(
|
|
254 Expression.Convert(expr, typeof(IQueryable<TElement>)),
|
|
255 Expression.Parameter(typeof(IDataContext), "ctx"),
|
|
256 keyParam,
|
|
257 paramArray);
|
|
258
|
|
259 var itemReader = CompiledQuery.Compile(lambda);
|
|
260 var keyExpr = context._key.BuildExpression(null, 0);
|
|
261 var keyReader = Expression.Lambda<Func<QueryContext,IDataContext,IDataReader,Expression,object[],TKey>>(
|
|
262 keyExpr,
|
|
263 new []
|
|
264 {
|
|
265 ExpressionBuilder.ContextParam,
|
|
266 ExpressionBuilder.DataContextParam,
|
|
267 ExpressionBuilder.DataReaderParam,
|
|
268 ExpressionBuilder.ExpressionParam,
|
|
269 ExpressionBuilder.ParametersParam,
|
|
270 });
|
|
271
|
|
272 return Expression.Call(
|
|
273 null,
|
|
274 ReflectionHelper.Expressor<object>.MethodExpressor(_ => GetGrouping(null, null, null, null, null, null, null, null)),
|
|
275 new Expression[]
|
|
276 {
|
|
277 ExpressionBuilder.ContextParam,
|
|
278 ExpressionBuilder.DataContextParam,
|
|
279 ExpressionBuilder.DataReaderParam,
|
|
280 Expression.Constant(context.Builder.CurrentSqlParameters),
|
|
281 ExpressionBuilder.ExpressionParam,
|
|
282 ExpressionBuilder.ParametersParam,
|
|
283 Expression.Constant(keyReader.Compile()),
|
|
284 Expression.Constant(itemReader),
|
|
285 });
|
|
286 }
|
|
287
|
|
288 static IGrouping<TKey,TElement> GetGrouping(
|
|
289 QueryContext context,
|
|
290 IDataContext dataContext,
|
|
291 IDataReader dataReader,
|
|
292 List<ParameterAccessor> parameterAccessor,
|
|
293 Expression expr,
|
|
294 object[] ps,
|
|
295 Func<QueryContext,IDataContext,IDataReader,Expression,object[],TKey> keyReader,
|
|
296 Func<IDataContext,TKey,object[],IQueryable<TElement>> itemReader)
|
|
297 {
|
|
298 var key = keyReader(context, dataContext, dataReader, expr, ps);
|
|
299 return new Grouping<TKey,TElement>(key, context, parameterAccessor, itemReader);
|
|
300 }
|
|
301 }
|
|
302
|
|
303 Expression BuildGrouping()
|
|
304 {
|
|
305 var gtype = typeof(GroupByHelper<,,>).MakeGenericType(
|
|
306 _key.Lambda.Body.Type,
|
|
307 _element.Lambda.Body.Type,
|
|
308 _key.Lambda.Parameters[0].Type);
|
|
309
|
|
310 var isBlockDisable = Builder.IsBlockDisable;
|
|
311
|
|
312 Builder.IsBlockDisable = true;
|
|
313
|
|
314 var helper = (IGroupByHelper)Activator.CreateInstance(gtype);
|
|
315 var expr = helper.GetGrouping(this);
|
|
316
|
|
317 Builder.IsBlockDisable = isBlockDisable;
|
|
318
|
|
319 return expr;
|
|
320 }
|
|
321
|
|
322 public override Expression BuildExpression(Expression expression, int level)
|
|
323 {
|
|
324 if (expression == null)
|
|
325 return BuildGrouping();
|
|
326
|
|
327 if (level != 0)
|
|
328 {
|
|
329 var levelExpression = expression.GetLevelExpression(level);
|
|
330
|
|
331 if (levelExpression.NodeType == ExpressionType.MemberAccess)
|
|
332 {
|
|
333 var ma = (MemberExpression)levelExpression;
|
|
334
|
|
335 if (ma.Member.Name == "Key" && ma.Member.DeclaringType == _groupingType)
|
|
336 {
|
|
337 return levelExpression == expression ?
|
|
338 _key.BuildExpression(null, 0) :
|
|
339 _key.BuildExpression(expression, level + 1);
|
|
340 }
|
|
341 }
|
|
342 }
|
|
343
|
|
344 throw new InvalidOperationException();
|
|
345 }
|
|
346
|
|
347 ISqlExpression ConvertEnumerable(MethodCallExpression call)
|
|
348 {
|
|
349 if (AggregationBuilder.MethodNames.Contains(call.Method.Name))
|
|
350 {
|
|
351 if (call.Arguments[0].NodeType == ExpressionType.Call)
|
|
352 {
|
|
353 var arg = (MethodCallExpression)call.Arguments[0];
|
|
354
|
|
355 if (arg.Method.Name == "Select")
|
|
356 {
|
|
357 if (arg.Arguments[0].NodeType != ExpressionType.Call)
|
|
358 {
|
|
359 var l = (LambdaExpression)arg.Arguments[1].Unwrap();
|
|
360 var largs = l.Type.GetGenericArguments();
|
|
361
|
|
362 if (largs.Length == 2)
|
|
363 {
|
|
364 var p = _element.Parent;
|
|
365 var ctx = new ExpressionContext(Parent, _element, l);
|
|
366 var sql = Builder.ConvertToSql(ctx, l.Body, true);
|
|
367
|
|
368 Builder.ReplaceParent(ctx, p);
|
|
369
|
|
370 return new SqlFunction(call.Type, call.Method.Name, sql);
|
|
371 }
|
|
372 }
|
|
373 }
|
|
374 }
|
|
375 }
|
|
376
|
|
377 if (call.Arguments[0].NodeType == ExpressionType.Call)
|
|
378 {
|
|
379 var ctx = Builder.GetSubQuery(this, call);
|
|
380
|
|
381 if (Builder.SqlProvider.IsSubQueryColumnSupported)
|
|
382 return ctx.SqlQuery;
|
|
383
|
|
384 var join = ctx.SqlQuery.CrossApply();
|
|
385
|
|
386 SqlQuery.From.Tables[0].Joins.Add(join.JoinedTable);
|
|
387
|
|
388 return ctx.SqlQuery.Select.Columns[0];
|
|
389 }
|
|
390
|
|
391 var args = new ISqlExpression[call.Arguments.Count - 1];
|
|
392
|
|
393 if (CountBuilder.MethodNames.Contains(call.Method.Name))
|
|
394 {
|
|
395 if (args.Length > 0)
|
|
396 throw new InvalidOperationException();
|
|
397
|
|
398 return SqlFunction.CreateCount(call.Type, SqlQuery);
|
|
399 }
|
|
400
|
|
401 if (call.Arguments.Count > 1)
|
|
402 {
|
|
403 for (var i = 1; i < call.Arguments.Count; i++)
|
|
404 {
|
|
405 var ex = call.Arguments[i].Unwrap();
|
|
406
|
|
407 if (ex is LambdaExpression)
|
|
408 {
|
|
409 var l = (LambdaExpression)ex;
|
|
410 var p = _element.Parent;
|
|
411 var ctx = new ExpressionContext(Parent, _element, l);
|
|
412
|
|
413 args[i - 1] = Builder.ConvertToSql(ctx, l.Body, true);
|
|
414
|
|
415 Builder.ReplaceParent(ctx, p);
|
|
416 }
|
|
417 else
|
|
418 {
|
|
419 throw new InvalidOperationException();
|
|
420 }
|
|
421 }
|
|
422 }
|
|
423 else
|
|
424 {
|
|
425 args = _element.ConvertToSql(null, 0, ConvertFlags.Field).Select(_ => _.Sql).ToArray();
|
|
426 }
|
|
427
|
|
428 return new SqlFunction(call.Type, call.Method.Name, args);
|
|
429 }
|
|
430
|
|
431 PropertyInfo _keyProperty;
|
|
432
|
|
433 public override SqlInfo[] ConvertToSql(Expression expression, int level, ConvertFlags flags)
|
|
434 {
|
|
435 if (expression == null)
|
|
436 return _key.ConvertToSql(null, 0, flags);
|
|
437
|
|
438 if (level > 0)
|
|
439 {
|
|
440 switch (expression.NodeType)
|
|
441 {
|
|
442 case ExpressionType.Call :
|
|
443 {
|
|
444 var e = (MethodCallExpression)expression;
|
|
445
|
|
446 if (e.Method.DeclaringType == typeof(Enumerable))
|
|
447 {
|
|
448 return new[] { new SqlInfo { Sql = ConvertEnumerable(e) } };
|
|
449 }
|
|
450
|
|
451 break;
|
|
452 }
|
|
453
|
|
454 case ExpressionType.MemberAccess :
|
|
455 {
|
|
456 var levelExpression = expression.GetLevelExpression(level);
|
|
457
|
|
458 if (levelExpression.NodeType == ExpressionType.MemberAccess)
|
|
459 {
|
|
460 var e = (MemberExpression)levelExpression;
|
|
461
|
|
462 if (e.Member.Name == "Key")
|
|
463 {
|
|
464 if (_keyProperty == null)
|
|
465 _keyProperty = _groupingType.GetProperty("Key");
|
|
466
|
|
467 if (e.Member == _keyProperty)
|
|
468 {
|
|
469 if (levelExpression == expression)
|
|
470 return _key.ConvertToSql(null, 0, flags);
|
|
471
|
|
472 return _key.ConvertToSql(expression, level + 1, flags);
|
|
473 }
|
|
474 }
|
|
475
|
|
476 return Sequence.ConvertToSql(expression, level, flags);
|
|
477 }
|
|
478
|
|
479 break;
|
|
480 }
|
|
481 }
|
|
482 }
|
|
483
|
|
484 throw new InvalidOperationException();
|
|
485 }
|
|
486
|
|
487 readonly Dictionary<Tuple<Expression,int,ConvertFlags>,SqlInfo[]> _expressionIndex = new Dictionary<Tuple<Expression,int,ConvertFlags>,SqlInfo[]>();
|
|
488
|
|
489 public override SqlInfo[] ConvertToIndex(Expression expression, int level, ConvertFlags flags)
|
|
490 {
|
|
491 var key = Tuple.Create(expression, level, flags);
|
|
492
|
|
493 SqlInfo[] info;
|
|
494
|
|
495 if (!_expressionIndex.TryGetValue(key, out info))
|
|
496 {
|
|
497 info = ConvertToSql(expression, level, flags);
|
|
498
|
|
499 foreach (var item in info)
|
|
500 {
|
|
501 item.Query = SqlQuery;
|
|
502 item.Index = SqlQuery.Select.Add(item.Sql);
|
|
503 }
|
|
504 }
|
|
505
|
|
506 return info;
|
|
507 }
|
|
508
|
|
509 public override IsExpressionResult IsExpression(Expression expression, int level, RequestFor requestFlag)
|
|
510 {
|
|
511 if (level != 0)
|
|
512 {
|
|
513 var levelExpression = expression.GetLevelExpression(level);
|
|
514
|
|
515 if (levelExpression.NodeType == ExpressionType.MemberAccess)
|
|
516 {
|
|
517 var ma = (MemberExpression)levelExpression;
|
|
518
|
|
519 if (ma.Member.Name == "Key" && ma.Member.DeclaringType == _groupingType)
|
|
520 {
|
|
521 return levelExpression == expression ?
|
|
522 _key.IsExpression(null, 0, requestFlag) :
|
|
523 _key.IsExpression(expression, level + 1, requestFlag);
|
|
524 }
|
|
525 }
|
|
526 }
|
|
527
|
|
528 return IsExpressionResult.False;
|
|
529 }
|
|
530
|
|
531 public override int ConvertToParentIndex(int index, IBuildContext context)
|
|
532 {
|
|
533 var expr = SqlQuery.Select.Columns[index].Expression;
|
|
534
|
|
535 if (!SqlQuery.GroupBy.Items.Exists(_ => _ == expr || (expr is SqlQuery.Column && _ == ((SqlQuery.Column)expr).Expression)))
|
|
536 SqlQuery.GroupBy.Items.Add(expr);
|
|
537
|
|
538 return base.ConvertToParentIndex(index, this);
|
|
539 }
|
|
540
|
|
541 interface IContextHelper
|
|
542 {
|
|
543 Expression GetContext(Expression sequence, ParameterExpression param, Expression expr1, Expression expr2);
|
|
544 }
|
|
545
|
|
546 class ContextHelper<T> : IContextHelper
|
|
547 {
|
|
548 public Expression GetContext(Expression sequence, ParameterExpression param, Expression expr1, Expression expr2)
|
|
549 {
|
|
550 // ReSharper disable AssignNullToNotNullAttribute
|
|
551 //ReflectionHelper.Expressor<object>.MethodExpressor(_ => Queryable.Where(null, (Expression<Func<T,bool>>)null)),
|
|
552 var mi = ReflectionHelper.Expressor<object>.MethodExpressor(_ => Enumerable.Where(null, (Func<T,bool>)null));
|
|
553 // ReSharper restore AssignNullToNotNullAttribute
|
|
554 var arg2 = Expression.Lambda<Func<T,bool>>(Expression.Equal(expr1, expr2), new[] { param });
|
|
555
|
|
556 return Expression.Call(null, mi, sequence, arg2);
|
|
557 }
|
|
558 }
|
|
559
|
|
560 public override IBuildContext GetContext(Expression expression, int level, BuildInfo buildInfo)
|
|
561 {
|
|
562 if (expression == null && buildInfo != null)
|
|
563 {
|
|
564 if (buildInfo.Parent is SelectManyBuilder.SelectManyContext)
|
|
565 {
|
|
566 var sm = (SelectManyBuilder.SelectManyContext)buildInfo.Parent;
|
|
567 var ctype = typeof(ContextHelper<>).MakeGenericType(_key.Lambda.Parameters[0].Type);
|
|
568 var helper = (IContextHelper)Activator.CreateInstance(ctype);
|
|
569 var expr = helper.GetContext(
|
|
570 Sequence.Expression,
|
|
571 _key.Lambda.Parameters[0],
|
|
572 Expression.PropertyOrField(sm.Lambda.Parameters[0], "Key"),
|
|
573 _key.Lambda.Body);
|
|
574
|
|
575 return Builder.BuildSequence(new BuildInfo(buildInfo, expr));
|
|
576 }
|
|
577
|
|
578 //if (buildInfo.Parent == this)
|
|
579 {
|
|
580 var ctype = typeof(ContextHelper<>).MakeGenericType(_key.Lambda.Parameters[0].Type);
|
|
581 var helper = (IContextHelper)Activator.CreateInstance(ctype);
|
|
582 var expr = helper.GetContext(
|
|
583 _sequenceExpr,
|
|
584 _key.Lambda.Parameters[0],
|
|
585 Expression.PropertyOrField(buildInfo.Expression, "Key"),
|
|
586 _key.Lambda.Body);
|
|
587
|
|
588 var ctx = Builder.BuildSequence(new BuildInfo(buildInfo, expr));
|
|
589
|
|
590 ctx.SqlQuery.Properties.Add(Tuple.Create("from_group_by", SqlQuery));
|
|
591
|
|
592 return ctx;
|
|
593 }
|
|
594
|
|
595 //return this;
|
|
596 }
|
|
597
|
|
598 if (level != 0)
|
|
599 {
|
|
600 var levelExpression = expression.GetLevelExpression(level);
|
|
601
|
|
602 if (levelExpression.NodeType == ExpressionType.MemberAccess)
|
|
603 {
|
|
604 var ma = (MemberExpression)levelExpression;
|
|
605
|
|
606 if (ma.Member.Name == "Key" && ma.Member.DeclaringType == _groupingType)
|
|
607 {
|
|
608 return levelExpression == expression ?
|
|
609 _key.GetContext(null, 0, buildInfo) :
|
|
610 _key.GetContext(expression, level + 1, buildInfo);
|
|
611 }
|
|
612 }
|
|
613 }
|
|
614
|
|
615 throw new InvalidOperationException();
|
|
616 }
|
|
617 }
|
|
618
|
|
619 #endregion
|
|
620 }
|
|
621 }
|