comparison Source/Data/Linq/Builder/SelectContext.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.Generic;
3 using System.Linq;
4 using System.Linq.Expressions;
5 using System.Reflection;
6
7 namespace BLToolkit.Data.Linq.Builder
8 {
9 using BLToolkit.Linq;
10 using Data.Sql;
11 using Reflection;
12
13 // This class implements double functionality (scalar and member type selects)
14 // and could be implemented as two different classes.
15 // But the class means to have a lot of inheritors, and functionality of the inheritors
16 // will be doubled as well. So lets double it once here.
17 //
18 public class SelectContext : IBuildContext
19 {
20 #region Init
21
22 #if DEBUG
23 [CLSCompliant(false)]
24 public string _sqlQueryText { get { return SqlQuery == null ? "" : SqlQuery.SqlText; } }
25
26 public MethodCallExpression MethodCall;
27 #endif
28
29 public IBuildContext[] Sequence { get; set; }
30 public LambdaExpression Lambda { get; set; }
31 public Expression Body { get; set; }
32 public ExpressionBuilder Builder { get; private set; }
33 public SqlQuery SqlQuery { get; set; }
34 public IBuildContext Parent { get; set; }
35 public bool IsScalar { get; private set; }
36
37 Expression IBuildContext.Expression { get { return Lambda; } }
38
39 public readonly Dictionary<MemberInfo,Expression> Members = new Dictionary<MemberInfo,Expression>(new MemberInfoComparer());
40
41 public SelectContext(IBuildContext parent, LambdaExpression lambda, params IBuildContext[] sequences)
42 {
43 Parent = parent;
44 Sequence = sequences;
45 Builder = sequences[0].Builder;
46 Lambda = lambda;
47 Body = lambda.Body;
48 SqlQuery = sequences[0].SqlQuery;
49
50 foreach (var context in Sequence)
51 context.Parent = this;
52
53 IsScalar = !Builder.ProcessProjection(Members, Body);
54
55 Builder.Contexts.Add(this);
56 }
57
58 #endregion
59
60 #region BuildQuery
61
62 public virtual void BuildQuery<T>(Query<T> query, ParameterExpression queryParameter)
63 {
64 var expr = BuildExpression(null, 0);
65 var mapper = Builder.BuildMapper<T>(expr);
66
67 query.SetQuery(mapper.Compile());
68 }
69
70 #endregion
71
72 #region BuildExpression
73
74 public virtual Expression BuildExpression(Expression expression, int level)
75 {
76 {
77 var key = Tuple.Create(expression, level, ConvertFlags.Field);
78
79 SqlInfo[] info;
80
81 if (_expressionIndex.TryGetValue(key, out info))
82 {
83 var idx = Parent == null ? info[0].Index : Parent.ConvertToParentIndex(info[0].Index, this);
84 return Builder.BuildSql((expression ?? Body).Type, idx);
85 }
86 }
87
88 if (expression == null)
89 return Builder.BuildExpression(this, Body);
90
91 var levelExpression = expression.GetLevelExpression(level);
92
93 if (IsScalar)
94 {
95 if (Body.NodeType != ExpressionType.Parameter && level == 0)
96 if (levelExpression == expression)
97 if (IsSubQuery() && IsExpression(null, 0, RequestFor.Expression).Result)
98 {
99 var info = ConvertToIndex(expression, level, ConvertFlags.Field).Single();
100 var idx = Parent == null ? info.Index : Parent.ConvertToParentIndex(info.Index, this);
101
102 return Builder.BuildSql(expression.Type, idx);
103 }
104
105 return ProcessScalar(
106 expression,
107 level,
108 (ctx, ex, l) => ctx.BuildExpression(ex, l),
109 () => GetSequence(expression, level).BuildExpression(null, 0));
110 }
111 else
112 {
113 if (level == 0)
114 {
115 var sequence = GetSequence(expression, level);
116
117 return levelExpression == expression ?
118 sequence.BuildExpression(null, 0) :
119 sequence.BuildExpression(expression, level + 1);
120 }
121
122 switch (levelExpression.NodeType)
123 {
124 case ExpressionType.MemberAccess :
125 {
126 var memberExpression = GetMemberExpression(
127 ((MemberExpression)levelExpression).Member,
128 levelExpression == expression,
129 levelExpression.Type);
130
131 if (levelExpression == expression)
132 {
133 if (IsSubQuery())
134 {
135 switch (memberExpression.NodeType)
136 {
137 case ExpressionType.New :
138 case ExpressionType.MemberInit :
139 {
140 return memberExpression.Convert(e =>
141 {
142 if (e != memberExpression)
143 {
144 switch (e.NodeType)
145 {
146 case ExpressionType.MemberAccess :
147 var sequence = GetSequence(memberExpression, 0);
148
149 if (sequence != null &&
150 !sequence.IsExpression(e, 0, RequestFor.Object).Result &&
151 !sequence.IsExpression(e, 0, RequestFor.Field). Result)
152 {
153 var info = ConvertToIndex(e, 0, ConvertFlags.Field).Single();
154 var idx = Parent == null ? info.Index : Parent.ConvertToParentIndex(info.Index, this);
155
156 return Builder.BuildSql(e.Type, idx);
157 }
158
159 return Builder.BuildExpression(this, e);
160 }
161 }
162
163 return e;
164 });
165 }
166 }
167
168 var me = memberExpression.NodeType == ExpressionType.Parameter ? null : memberExpression;
169
170 if (!IsExpression(me, 0, RequestFor.Object).Result &&
171 !IsExpression(me, 0, RequestFor.Field). Result)
172 {
173 var info = ConvertToIndex(expression, level, ConvertFlags.Field).Single();
174 var idx = Parent == null ? info.Index : Parent.ConvertToParentIndex(info.Index, this);
175
176 return Builder.BuildSql(expression.Type, idx);
177 }
178 }
179
180 return Builder.BuildExpression(this, memberExpression);
181 }
182
183 {
184 var sequence = GetSequence(expression, level);
185
186 switch (memberExpression.NodeType)
187 {
188 case ExpressionType.Parameter :
189 {
190 var parameter = Lambda.Parameters[Sequence.Length == 0 ? 0 : Array.IndexOf(Sequence, sequence)];
191
192 if (memberExpression == parameter)
193 return sequence.BuildExpression(expression, level + 1);
194
195 break;
196
197 }
198
199 case ExpressionType.New :
200 case ExpressionType.MemberInit :
201 {
202 var mmExpresion = GetMemberExpression(memberExpression, expression, level + 1);
203 return Builder.BuildExpression(this, mmExpresion);
204 }
205 }
206
207 var expr = expression.Convert(ex => ex == levelExpression ? memberExpression : ex);
208
209 return sequence.BuildExpression(expr, 1);
210 }
211 }
212
213 case ExpressionType.Parameter :
214 break;
215 }
216 }
217
218 throw new InvalidOperationException();
219 }
220
221 #endregion
222
223 #region ConvertToSql
224
225 readonly Dictionary<MemberInfo,SqlInfo[]> _sql = new Dictionary<MemberInfo,SqlInfo[]>(new MemberInfoComparer());
226
227 public virtual SqlInfo[] ConvertToSql(Expression expression, int level, ConvertFlags flags)
228 {
229 if (expression != null && level > 0 && expression.NodeType == ExpressionType.Call)
230 {
231 var e = (MethodCallExpression)expression;
232
233 if (e.Method.DeclaringType == typeof(Enumerable))
234 {
235 return new[] { new SqlInfo { Sql = Builder.SubQueryToSql(this, e) } };
236 }
237 }
238
239 if (IsScalar)
240 {
241 if (expression == null)
242 return Builder.ConvertExpressions(this, Body, flags);
243
244 switch (flags)
245 {
246 case ConvertFlags.Field :
247 case ConvertFlags.Key :
248 case ConvertFlags.All :
249 {
250 if (Body.NodeType != ExpressionType.Parameter && level == 0)
251 {
252 var levelExpression = expression.GetLevelExpression(level);
253
254 if (levelExpression != expression)
255 if (flags != ConvertFlags.Field && IsExpression(expression, level, RequestFor.Field).Result)
256 flags = ConvertFlags.Field;
257 }
258
259 return ProcessScalar(
260 expression,
261 level,
262 (ctx, ex, l) => ctx.ConvertToSql(ex, l, flags),
263 () => new[] { new SqlInfo { Sql = Builder.ConvertToSql(this, expression, false) } });
264 }
265 }
266 }
267 else
268 {
269 if (expression == null)
270 {
271 if (flags != ConvertFlags.Field)
272 {
273 var q =
274 from m in Members
275 where !(m.Key is MethodInfo)
276 select ConvertMember(m.Key, m.Value, flags) into mm
277 from m in mm
278 select m;
279
280 return q.ToArray();
281 }
282
283 throw new InvalidOperationException();
284 }
285
286 switch (flags)
287 {
288 case ConvertFlags.All :
289 case ConvertFlags.Key :
290 case ConvertFlags.Field :
291 {
292 var levelExpression = expression.GetLevelExpression(level);
293
294 switch (levelExpression.NodeType)
295 {
296 case ExpressionType.MemberAccess :
297 {
298 if (level != 0 && levelExpression == expression)
299 {
300 var member = ((MemberExpression)levelExpression).Member;
301
302 SqlInfo[] sql;
303
304 if (!_sql.TryGetValue(member, out sql))
305 {
306 var memberExpression = GetMemberExpression(
307 member, levelExpression == expression, levelExpression.Type);
308
309 sql = ConvertExpressions(memberExpression, flags)
310 .Select(si => si.Clone(member)).ToArray();
311
312 _sql.Add(member, sql);
313 }
314
315 return sql;
316 }
317
318 return ProcessMemberAccess(
319 expression, (MemberExpression)levelExpression, level,
320 (n,ctx,ex,l,mex) =>
321 {
322 switch (n)
323 {
324 case 0 :
325 var buildExpression = GetExpression(expression, levelExpression, mex);
326 return ConvertExpressions(buildExpression, flags);
327 default:
328 return ctx.ConvertToSql(ex, l, flags);
329 }
330 });
331 }
332
333 case ExpressionType.Parameter:
334 if (levelExpression != expression)
335 return GetSequence(expression, level).ConvertToSql(expression, level + 1, flags);
336
337 if (level == 0)
338 return GetSequence(expression, level).ConvertToSql(null, 0, flags);
339
340 break;
341
342 default:
343 if (level == 0)
344 return Builder.ConvertExpressions(this, expression, flags);
345 break;
346 }
347
348 break;
349 }
350 }
351 }
352
353 throw new InvalidOperationException();
354 }
355
356 SqlInfo[] ConvertMember(MemberInfo member, Expression expression, ConvertFlags flags)
357 {
358 return ConvertExpressions(expression, flags)
359 .Select(si => si.Clone(member))
360 .ToArray();
361 }
362
363 SqlInfo[] ConvertExpressions(Expression expression, ConvertFlags flags)
364 {
365 return Builder.ConvertExpressions(this, expression, flags)
366 .Select(CheckExpression)
367 .ToArray();
368 }
369
370 SqlInfo CheckExpression(SqlInfo expression)
371 {
372 if (expression.Sql is SqlQuery.SearchCondition)
373 {
374 expression.Sql = Builder.Convert(this, new SqlFunction(typeof(bool), "CASE", expression.Sql, new SqlValue(true), new SqlValue(false)));
375 }
376
377 return expression;
378 }
379
380 #endregion
381
382 #region ConvertToIndex
383
384 readonly Dictionary<Tuple<Expression,int,ConvertFlags>,SqlInfo[]> _expressionIndex = new Dictionary<Tuple<Expression,int,ConvertFlags>,SqlInfo[]>();
385
386 public virtual SqlInfo[] ConvertToIndex(Expression expression, int level, ConvertFlags flags)
387 {
388 var key = Tuple.Create(expression, level, flags);
389
390 SqlInfo[] info;
391
392 if (!_expressionIndex.TryGetValue(key, out info))
393 {
394 info = ConvertToIndexInternal(expression, level, flags);
395
396 var newInfo = info
397 .Select(i =>
398 {
399 if (i.Query == SqlQuery)
400 return i;
401
402 return new SqlInfo(i.Members)
403 {
404 Query = SqlQuery,
405 Index = SqlQuery.Select.Add(i.Query.Select.Columns[i.Index])
406 };
407 })
408 .ToArray();
409
410 _expressionIndex.Add(key, newInfo);
411
412 return newInfo;
413 }
414
415 return info;
416 }
417
418 readonly Dictionary<Tuple<MemberInfo,ConvertFlags>,SqlInfo[]> _memberIndex = new Dictionary<Tuple<MemberInfo,ConvertFlags>,SqlInfo[]>();
419
420 SqlInfo[] ConvertToIndexInternal(Expression expression, int level, ConvertFlags flags)
421 {
422 if (IsScalar)
423 {
424 if (Body.NodeType == ExpressionType.Parameter)
425 for (var i = 0; i < Sequence.Length; i++)
426 if (Body == Lambda.Parameters[i])
427 return Sequence[i].ConvertToIndex(expression, level, flags);
428
429 if (expression == null)
430 {
431 var key = Tuple.Create((MemberInfo)null, flags);
432
433 SqlInfo[] idx;
434
435 if (!_memberIndex.TryGetValue(key, out idx))
436 {
437 idx = ConvertToSql(null, 0, flags);
438
439 foreach (var info in idx)
440 SetInfo(info);
441
442 _memberIndex.Add(key, idx);
443 }
444
445 return idx;
446 }
447
448 switch (flags)
449 {
450 case ConvertFlags.Field :
451 case ConvertFlags.All :
452 return ProcessScalar(
453 expression,
454 level,
455 (ctx, ex, l) => ctx.ConvertToIndex(ex, l, flags),
456 () => GetSequence(expression, level).ConvertToIndex(expression, level + 1, flags));
457 }
458 }
459 else
460 {
461 if (expression == null)
462 {
463 switch (flags)
464 {
465 case ConvertFlags.Field : throw new InvalidOperationException();
466 case ConvertFlags.Key :
467 case ConvertFlags.All :
468 {
469 var p = Expression.Parameter(Body.Type, "p");
470 var q =
471 from m in Members.Keys
472 where !(m is MethodInfo)
473 select new
474 {
475 Sql = ConvertToIndex(Expression.MakeMemberAccess(p, m), 1, flags),
476 Member = m
477 } into mm
478 from m in mm.Sql.Select(s => s.Clone(mm.Member))
479 select m;
480
481 return q.ToArray();
482 }
483 }
484 }
485
486 switch (flags)
487 {
488 case ConvertFlags.All :
489 case ConvertFlags.Key :
490 case ConvertFlags.Field :
491 {
492 if (level == 0)
493 {
494 var idx = Builder.ConvertExpressions(this, expression, flags);
495
496 foreach (var info in idx)
497 SetInfo(info);
498
499 return idx;
500 }
501
502 var levelExpression = expression.GetLevelExpression(level);
503
504 switch (levelExpression.NodeType)
505 {
506 case ExpressionType.MemberAccess :
507 {
508 if (levelExpression == expression)
509 {
510 var member = Tuple.Create(((MemberExpression)levelExpression).Member, flags);
511
512 SqlInfo[] idx;
513
514 if (!_memberIndex.TryGetValue(member, out idx))
515 {
516 idx = ConvertToSql(expression, level, flags);
517
518 if (flags == ConvertFlags.Field && idx.Length != 1)
519 throw new InvalidOperationException();
520
521 foreach (var info in idx)
522 SetInfo(info);
523
524 _memberIndex.Add(member, idx);
525 }
526
527 return idx;
528 }
529
530 return ProcessMemberAccess(
531 expression,
532 (MemberExpression)levelExpression,
533 level,
534 (n, ctx, ex, l, _) => n == 0 ?
535 GetSequence(expression, level).ConvertToIndex(expression, level + 1, flags) :
536 ctx.ConvertToIndex(ex, l, flags));
537 }
538
539 case ExpressionType.Parameter:
540
541 if (levelExpression != expression)
542 return GetSequence(expression, level).ConvertToIndex(expression, level + 1, flags);
543 break;
544 }
545
546 break;
547 }
548 }
549 }
550
551 throw new InvalidOperationException();
552 }
553
554 void SetInfo(SqlInfo info)
555 {
556 info.Query = SqlQuery;
557
558 if (info.Sql == SqlQuery)
559 info.Index = SqlQuery.Select.Columns.Count - 1;
560 else
561 info.Index = SqlQuery.Select.Add(info.Sql);
562 }
563
564 #endregion
565
566 #region IsExpression
567
568 public virtual IsExpressionResult IsExpression(Expression expression, int level, RequestFor requestFlag)
569 {
570 switch (requestFlag)
571 {
572 case RequestFor.SubQuery : return IsExpressionResult.False;
573 case RequestFor.Root :
574 return new IsExpressionResult(Sequence.Length == 1 ?
575 expression == Lambda.Parameters[0] :
576 Lambda.Parameters.Any(p => p == expression));
577 }
578
579 if (IsScalar)
580 {
581 if (expression == null)
582 return IsExpression(Body, 0, requestFlag);
583
584 switch (requestFlag)
585 {
586 default : return IsExpressionResult.False;
587 case RequestFor.Table :
588 case RequestFor.Association :
589 case RequestFor.Field :
590 case RequestFor.Expression :
591 case RequestFor.Object :
592 case RequestFor.GroupJoin :
593 return ProcessScalar(
594 expression,
595 level,
596 (ctx, ex, l) => ctx.IsExpression(ex, l, requestFlag),
597 () => new IsExpressionResult(requestFlag == RequestFor.Expression));
598 }
599 }
600 else
601 {
602 switch (requestFlag)
603 {
604 default : return IsExpressionResult.False;
605 case RequestFor.Table :
606 case RequestFor.Association :
607 case RequestFor.Field :
608 case RequestFor.Expression :
609 case RequestFor.Object :
610 case RequestFor.GroupJoin :
611 {
612 if (expression == null)
613 {
614 if (requestFlag == RequestFor.Expression)
615 return new IsExpressionResult(Members.Values.Any(member => IsExpression(member, 0, requestFlag).Result));
616
617 return new IsExpressionResult(requestFlag == RequestFor.Object);
618 }
619
620 var levelExpression = expression.GetLevelExpression(level);
621
622 switch (levelExpression.NodeType)
623 {
624 case ExpressionType.MemberAccess :
625 {
626 var member = ((MemberExpression)levelExpression).Member;
627
628 Expression memberExpression;
629
630 if (!Members.TryGetValue(member, out memberExpression))
631 {
632 var nm = Members.Keys.FirstOrDefault(m => m.Name == member.Name);
633
634 if (nm != null && member.DeclaringType.IsInterface)
635 {
636 if (TypeHelper.IsSameOrParent(member.DeclaringType, nm.DeclaringType))
637 memberExpression = Members[nm];
638 else
639 {
640 var mdt = TypeHelper.GetDefiningTypes(member.DeclaringType, member);
641 var ndt = TypeHelper.GetDefiningTypes(Body.Type, nm);
642
643 if (mdt.Intersect(ndt).Any())
644 memberExpression = Members[nm];
645 }
646 }
647
648 if (memberExpression == null)
649 return new IsExpressionResult(requestFlag == RequestFor.Expression);
650 //throw new InvalidOperationException(
651 // string.Format("Invalid member '{0}.{1}'", member.DeclaringType, member.Name));
652 }
653
654 if (levelExpression == expression)
655 {
656 switch (memberExpression.NodeType)
657 {
658 case ExpressionType.New :
659 case ExpressionType.MemberInit :
660 return new IsExpressionResult(requestFlag == RequestFor.Object);
661 }
662 }
663
664 return ProcessMemberAccess(
665 expression,
666 (MemberExpression)levelExpression,
667 level,
668 (n,ctx,ex,l,_) => n == 0 ?
669 new IsExpressionResult(requestFlag == RequestFor.Expression) :
670 ctx.IsExpression(ex, l, requestFlag));
671 }
672
673 case ExpressionType.Parameter :
674 {
675 var sequence = GetSequence(expression, level);
676 var parameter = Lambda.Parameters[Sequence.Length == 0 ? 0 : Array.IndexOf(Sequence, sequence)];
677
678 if (levelExpression == expression)
679 {
680 if (levelExpression == parameter)
681 return sequence.IsExpression(null, 0, requestFlag);
682 }
683 else if (level == 0)
684 return sequence.IsExpression(expression, 1, requestFlag);
685
686 break;
687 }
688
689 case ExpressionType.New :
690 case ExpressionType.MemberInit : return new IsExpressionResult(requestFlag == RequestFor.Object);
691 default : return new IsExpressionResult(requestFlag == RequestFor.Expression);
692 }
693
694 break;
695 }
696 }
697 }
698
699 throw new InvalidOperationException();
700 }
701
702 #endregion
703
704 #region GetContext
705
706 public virtual IBuildContext GetContext(Expression expression, int level, BuildInfo buildInfo)
707 {
708 if (expression == null)
709 return this;
710
711 if (IsScalar)
712 {
713 return ProcessScalar(
714 expression,
715 level,
716 (ctx, ex, l) => ctx.GetContext(ex, l, buildInfo),
717 () => { throw new InvalidOperationException(); });
718 }
719 else
720 {
721 var levelExpression = expression.GetLevelExpression(level);
722
723 switch (levelExpression.NodeType)
724 {
725 case ExpressionType.MemberAccess :
726 {
727 if (levelExpression == expression && Sequence.Length == 1 && !(Sequence[0] is GroupByBuilder.GroupByContext))
728 {
729 var memberExpression = GetMemberExpression(
730 ((MemberExpression)levelExpression).Member,
731 levelExpression == expression,
732 levelExpression.Type);
733
734 //var sequence = GetSequence(memberExpression, 0);
735 //return sequence.GetContext(memberExpression, 1, new BuildInfo(buildInfo, memberExpression));
736
737 var ctx = GetContext(memberExpression, 0, new BuildInfo(this, memberExpression, buildInfo.SqlQuery));
738
739 if (ctx != null)
740 {
741 return ctx;
742 }
743 }
744
745 var context = ProcessMemberAccess(
746 expression,
747 (MemberExpression)levelExpression,
748 level,
749 (n,ctx,ex,l,_) => n == 0 ?
750 null :
751 ctx.GetContext(ex, l, buildInfo));
752
753 if (context == null)
754 throw new InvalidOperationException();
755
756 return context;
757 }
758
759 case ExpressionType.Parameter :
760 {
761 var sequence = GetSequence(expression, level);
762 var parameter = Lambda.Parameters[Sequence.Length == 0 ? 0 : Array.IndexOf(Sequence, sequence)];
763
764 if (levelExpression == expression)
765 {
766 if (levelExpression == parameter)
767 return sequence.GetContext(null, 0, buildInfo);
768 }
769 else if (level == 0)
770 return sequence.GetContext(expression, 1, buildInfo);
771
772 break;
773 }
774 }
775
776 if (level == 0)
777 {
778 var sequence = GetSequence(expression, level);
779 return sequence.GetContext(expression, level + 1, buildInfo);
780 }
781 }
782
783 throw new InvalidOperationException();
784 }
785
786 #endregion
787
788 #region ConvertToParentIndex
789
790 public virtual int ConvertToParentIndex(int index, IBuildContext context)
791 {
792 if (context.SqlQuery != SqlQuery)
793 index = SqlQuery.Select.Add(context.SqlQuery.Select.Columns[index]);
794
795 return Parent == null ? index : Parent.ConvertToParentIndex(index, this);
796 }
797
798 #endregion
799
800 #region SetAlias
801
802 public virtual void SetAlias(string alias)
803 {
804 }
805
806 #endregion
807
808 #region GetSubQuery
809
810 public ISqlExpression GetSubQuery(IBuildContext context)
811 {
812 return null;
813 }
814
815 #endregion
816
817 #region Helpers
818
819 T ProcessScalar<T>(Expression expression, int level, Func<IBuildContext,Expression,int,T> action, Func<T> defaultAction)
820 {
821 if (level == 0)
822 {
823 if (Body.NodeType == ExpressionType.Parameter)
824 {
825 var sequence = GetSequence(Body, 0);
826
827 return expression == Body ?
828 action(sequence, null, 0) :
829 action(sequence, expression, 1);
830 }
831
832 var levelExpression = expression.GetLevelExpression(level);
833
834 if (levelExpression != expression)
835 {
836 var ctx = GetSequence(expression, level);
837 return ctx == null ? defaultAction() : action(ctx, expression, Sequence.Contains(ctx) ? level + 1 : 0);
838 }
839
840 if (expression.NodeType == ExpressionType.Parameter)
841 {
842 var sequence = GetSequence(expression, level);
843 var parameter = Lambda.Parameters[Sequence.Length == 0 ? 0 : Array.IndexOf(Sequence, sequence)];
844
845 if (levelExpression == parameter)
846 return action(sequence, null, 0);
847 }
848
849 switch (Body.NodeType)
850 {
851 case ExpressionType.MemberAccess : return action(GetSequence(expression, level), null, 0);
852 default : return defaultAction();
853 }
854 }
855 else
856 {
857 var root = Body.GetRootObject();
858
859 if (root.NodeType == ExpressionType.Parameter)
860 {
861 var levelExpression = expression.GetLevelExpression(level - 1);
862 var newExpression = GetExpression(expression, levelExpression, Body);
863
864 return action(this, newExpression, 0);
865 }
866 }
867
868 throw new InvalidOperationException();
869 }
870
871 T ProcessMemberAccess<T>(Expression expression, MemberExpression levelExpression, int level,
872 Func<int,IBuildContext,Expression,int,Expression,T> action)
873 {
874 var memberExpression = Members[levelExpression.Member];
875 var newExpression = GetExpression(expression, levelExpression, memberExpression);
876 var sequence = GetSequence (expression, level);
877 var nextLevel = 1;
878
879 if (sequence != null)
880 {
881 var idx = Sequence.Length == 0 ? 0 : Array.IndexOf(Sequence, sequence);
882
883 if (idx >= 0)
884 {
885 var parameter = Lambda.Parameters[idx];
886
887 if (levelExpression == expression)
888 {
889 if (memberExpression == parameter)
890 return action(1, sequence, null, 0, memberExpression);
891
892 // if (!(sequence is GroupByBuilder.GroupByContext) && memberExpression.GetRootObject() == parameter)
893 // return action(3, this, newExpression, 0, memberExpression);
894 }
895 }
896 else
897 {
898 nextLevel = 0;
899 }
900 }
901
902 switch (memberExpression.NodeType)
903 {
904 case ExpressionType.MemberAccess :
905 case ExpressionType.Parameter :
906 if (sequence != null)
907 return action(2, sequence, newExpression, nextLevel, memberExpression);
908 throw new InvalidOperationException();
909
910 case ExpressionType.New :
911 case ExpressionType.MemberInit :
912 {
913 var mmExpresion = GetMemberExpression(memberExpression, expression, level + 1);
914 return action(3, this, mmExpresion, 0, memberExpression);
915 }
916 }
917
918 return action(0, this, null, 0, memberExpression);
919 }
920
921 protected bool IsSubQuery()
922 {
923 for (var p = Parent; p != null; p = p.Parent)
924 if (p.IsExpression(null, 0, RequestFor.SubQuery).Result)
925 return true;
926 return false;
927 }
928
929 IBuildContext GetSequence(Expression expression, int level)
930 {
931 if (Sequence.Length == 1 && Sequence[0].Parent == null)
932 return Sequence[0];
933
934 Expression root = null;
935
936 if (IsScalar)
937 {
938 root = expression.GetRootObject();
939 }
940 else
941 {
942 var levelExpression = expression.GetLevelExpression(level);
943
944 switch (levelExpression.NodeType)
945 {
946 case ExpressionType.MemberAccess :
947 {
948 var memberExpression = Members[((MemberExpression)levelExpression).Member];
949
950 root = memberExpression.GetRootObject();
951
952 if (root.NodeType != ExpressionType.Parameter)
953 return null;
954
955 break;
956 }
957
958 case ExpressionType.Parameter :
959 {
960 root = expression.GetRootObject();
961 break;
962 }
963 }
964 }
965
966 if (root != null)
967 for (var i = 0; i < Lambda.Parameters.Count; i++)
968 if (root == Lambda.Parameters[i])
969 return Sequence[i];
970
971 foreach (var context in Sequence)
972 {
973 if (context.Parent != null)
974 {
975 var ctx = Builder.GetContext(context, root);
976 if (ctx != null)
977 return ctx;
978 }
979 }
980
981 return null;
982 }
983
984 static Expression GetExpression(Expression expression, Expression levelExpression, Expression memberExpression)
985 {
986 return levelExpression != expression ?
987 expression.Convert(ex => ex == levelExpression ? memberExpression : ex) :
988 memberExpression;
989 }
990
991 static Expression GetMemberExpression(Expression newExpression, Expression expression, int level)
992 {
993 var levelExpresion = expression.GetLevelExpression(level);
994
995 switch (newExpression.NodeType)
996 {
997 case ExpressionType.New :
998 case ExpressionType.MemberInit : break;
999 default :
1000 var le = expression.GetLevelExpression(level - 1);
1001 return GetExpression(expression, le, newExpression);
1002 }
1003
1004 if (levelExpresion.NodeType != ExpressionType.MemberAccess)
1005 throw new LinqException("Invalid expression {0}", levelExpresion);
1006
1007 var me = (MemberExpression)levelExpresion;
1008
1009 switch (newExpression.NodeType)
1010 {
1011 case ExpressionType.New:
1012 {
1013 var expr = (NewExpression)newExpression;
1014
1015 // ReSharper disable ConditionIsAlwaysTrueOrFalse
1016 // ReSharper disable HeuristicUnreachableCode
1017 if (expr.Members == null)
1018 throw new LinqException("Invalid expression {0}", expression);
1019 // ReSharper restore HeuristicUnreachableCode
1020 // ReSharper restore ConditionIsAlwaysTrueOrFalse
1021
1022 for (var i = 0; i < expr.Members.Count; i++)
1023 if (me.Member == expr.Members[i])
1024 return levelExpresion == expression ?
1025 expr.Arguments[i].Unwrap() :
1026 GetMemberExpression(expr.Arguments[i].Unwrap(), expression, level + 1);
1027
1028 throw new LinqException("Invalid expression {0}", expression);
1029 }
1030
1031 case ExpressionType.MemberInit:
1032 {
1033 var expr = (MemberInitExpression)newExpression;
1034
1035 foreach (var binding in expr.Bindings.Cast<MemberAssignment>())
1036 {
1037 if (me.Member == binding.Member)
1038 return levelExpresion == expression ?
1039 binding.Expression.Unwrap() :
1040 GetMemberExpression(binding.Expression.Unwrap(), expression, level + 1);
1041 }
1042
1043 throw new LinqException("Invalid expression {0}", expression);
1044 }
1045 }
1046
1047 return expression;
1048 }
1049
1050 Expression GetMemberExpression(MemberInfo member, bool add, Type type)
1051 {
1052 Expression memberExpression;
1053
1054 if (!Members.TryGetValue(member, out memberExpression))
1055 {
1056 foreach (var m in Members)
1057 {
1058 if (m.Key.Name == member.Name)
1059 {
1060 if (TypeHelper.Equals(m.Key, member, IsScalar ? null : Body.Type))
1061 return m.Value;
1062 }
1063 }
1064
1065 if (add && TypeHelper.IsSameOrParent(member.DeclaringType, Body.Type))
1066 {
1067 memberExpression = Expression.Constant(
1068 TypeHelper.GetDefaultValue(type), type);
1069
1070 Members.Add(member, memberExpression);
1071 }
1072 else
1073 throw new InvalidOperationException();
1074 }
1075
1076 return memberExpression;
1077 }
1078
1079 #endregion
1080 }
1081 }