Mercurial > pub > bltoolkit
comparison Source/Data/Linq/Builder/GroupByBuilder.cs @ 0:f990fcb411a9
Копия текущей версии из github
| author | cin |
|---|---|
| date | Thu, 27 Mar 2014 21:46:09 +0400 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:f990fcb411a9 |
|---|---|
| 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 } |
