0
|
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 }
|