comparison Source/Data/Linq/Builder/SubQueryContext.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
6 namespace BLToolkit.Data.Linq.Builder
7 {
8 using BLToolkit.Linq;
9 using Data.Sql;
10
11 class SubQueryContext : PassThroughContext
12 {
13 public readonly IBuildContext SubQuery;
14
15 public SubQueryContext(IBuildContext subQuery, SqlQuery sqlQuery, bool addToSql)
16 : base(subQuery)
17 {
18 if (sqlQuery == subQuery.SqlQuery)
19 throw new ArgumentException("Wrong subQuery argument.", "subQuery");
20
21 SubQuery = subQuery;
22 SubQuery.Parent = this;
23
24 SqlQuery = sqlQuery;
25
26 if (addToSql)
27 sqlQuery.From.Table(SubQuery.SqlQuery);
28 }
29
30 public SubQueryContext(IBuildContext subQuery, bool addToSql)
31 : this(subQuery, new SqlQuery { ParentSql = subQuery.SqlQuery.ParentSql }, addToSql)
32 {
33 }
34
35 public SubQueryContext(IBuildContext subQuery)
36 : this(subQuery, true)
37 {
38 }
39
40 public override SqlQuery SqlQuery { get; set; }
41 public override IBuildContext Parent { get; set; }
42
43 public override void BuildQuery<T>(Query<T> query, ParameterExpression queryParameter)
44 {
45 if (Expression.NodeType == ExpressionType.Lambda)
46 {
47 var le = (LambdaExpression)Expression;
48
49 if (le.Parameters.Count == 1 && null != Expression.Find(
50 e => e.NodeType == ExpressionType.Call && ((MethodCallExpression)e).IsQueryable()))
51 {
52 if (le.Body.NodeType == ExpressionType.New)
53 {
54 var ne = (NewExpression)le.Body;
55 var p = Expression.Parameter(ne.Type, "p");
56
57 var seq = new SelectContext(
58 Parent,
59 Expression.Lambda(
60 Expression.New(
61 ne.Constructor,
62 ne.Members.Select(m => Expression.MakeMemberAccess(p, m)).ToArray(),
63 ne.Members),
64 p),
65 this);
66
67 seq.BuildQuery(query, queryParameter);
68
69 return;
70 }
71
72 if (le.Body.NodeType == ExpressionType.MemberInit)
73 {
74 var mi = (MemberInitExpression)le.Body;
75
76 if (mi.NewExpression.Arguments.Count == 0 && mi.Bindings.All(b => b is MemberAssignment))
77 {
78 var p = Expression.Parameter(mi.Type, "p");
79
80 var seq = new SelectContext(
81 Parent,
82 Expression.Lambda(
83 Expression.MemberInit(
84 mi.NewExpression,
85 mi.Bindings
86 .OfType<MemberAssignment>()
87 .Select(ma => Expression.Bind(ma.Member, Expression.MakeMemberAccess(p, ma.Member)))
88 .ToArray()),
89 p),
90 this);
91
92 seq.BuildQuery(query, queryParameter);
93
94 return;
95 }
96 }
97 }
98 }
99
100 base.BuildQuery(query, queryParameter);
101 }
102
103 public override SqlInfo[] ConvertToSql(Expression expression, int level, ConvertFlags flags)
104 {
105 return SubQuery
106 .ConvertToIndex(expression, level, flags)
107 .Select(idx => new SqlInfo(idx.Members) { Sql = SubQuery.SqlQuery.Select.Columns[idx.Index] })
108 .ToArray();
109 }
110
111 // JoinContext has similar logic. Consider to review it.
112 //
113 public override SqlInfo[] ConvertToIndex(Expression expression, int level, ConvertFlags flags)
114 {
115 return ConvertToSql(expression, level, flags)
116 .Select(idx =>
117 {
118 idx.Query = SqlQuery;
119 idx.Index = GetIndex((SqlQuery.Column)idx.Sql);
120
121 return idx;
122 })
123 .ToArray();
124 }
125
126 public override IsExpressionResult IsExpression(Expression expression, int level, RequestFor testFlag)
127 {
128 switch (testFlag)
129 {
130 case RequestFor.SubQuery : return IsExpressionResult.True;
131 }
132
133 return base.IsExpression(expression, level, testFlag);
134 }
135
136 internal protected readonly Dictionary<ISqlExpression,int> ColumnIndexes = new Dictionary<ISqlExpression,int>();
137
138 protected virtual int GetIndex(SqlQuery.Column column)
139 {
140 int idx;
141
142 if (!ColumnIndexes.TryGetValue(column, out idx))
143 {
144 idx = SqlQuery.Select.Add(column);
145 ColumnIndexes.Add(column, idx);
146 }
147
148 return idx;
149 }
150
151 public override int ConvertToParentIndex(int index, IBuildContext context)
152 {
153 var idx = GetIndex(context.SqlQuery.Select.Columns[index]);
154 return Parent == null ? idx : Parent.ConvertToParentIndex(idx, this);
155 }
156
157 public override void SetAlias(string alias)
158 {
159 if (alias.Contains('<'))
160 return;
161
162 if (SqlQuery.From.Tables[0].Alias == null)
163 SqlQuery.From.Tables[0].Alias = alias;
164 }
165
166 public override ISqlExpression GetSubQuery(IBuildContext context)
167 {
168 return null;
169 }
170 }
171 }