Mercurial > pub > bltoolkit
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 } |