Mercurial > pub > bltoolkit
comparison Source/Data/Linq/Builder/SelectManyBuilder.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.Expressions; | |
4 | |
5 namespace BLToolkit.Data.Linq.Builder | |
6 { | |
7 using BLToolkit.Linq; | |
8 using Data.Sql; | |
9 | |
10 class SelectManyBuilder : MethodCallBuilder | |
11 { | |
12 protected override bool CanBuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo) | |
13 { | |
14 return | |
15 methodCall.IsQueryable("SelectMany") && | |
16 methodCall.Arguments.Count == 3 && | |
17 ((LambdaExpression)methodCall.Arguments[1].Unwrap()).Parameters.Count == 1; | |
18 } | |
19 | |
20 protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo) | |
21 { | |
22 var sequence = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0])); | |
23 var collectionSelector = (LambdaExpression)methodCall.Arguments[1].Unwrap(); | |
24 var resultSelector = (LambdaExpression)methodCall.Arguments[2].Unwrap(); | |
25 | |
26 if (!sequence.SqlQuery.GroupBy.IsEmpty) | |
27 { | |
28 sequence = new SubQueryContext(sequence); | |
29 } | |
30 | |
31 var context = new SelectManyContext(buildInfo.Parent, collectionSelector, sequence); | |
32 var expr = collectionSelector.Body.Unwrap(); | |
33 | |
34 var collectionInfo = new BuildInfo(context, expr, new SqlQuery()); | |
35 var collection = builder.BuildSequence(collectionInfo); | |
36 var leftJoin = collection is DefaultIfEmptyBuilder.DefaultIfEmptyContext; | |
37 var sql = collection.SqlQuery; | |
38 | |
39 var sequenceTables = new HashSet<ISqlTableSource>(sequence.SqlQuery.From.Tables[0].GetTables()); | |
40 var newQuery = null != new QueryVisitor().Find(sql, e => e == collectionInfo.SqlQuery); | |
41 var crossApply = null != new QueryVisitor().Find(sql, e => | |
42 e.ElementType == QueryElementType.TableSource && sequenceTables.Contains((ISqlTableSource)e) || | |
43 e.ElementType == QueryElementType.SqlField && sequenceTables.Contains(((SqlField)e).Table) || | |
44 e.ElementType == QueryElementType.Column && sequenceTables.Contains(((SqlQuery.Column)e).Parent)); | |
45 | |
46 if (collection is JoinBuilder.GroupJoinSubQueryContext) | |
47 { | |
48 var groupJoin = ((JoinBuilder.GroupJoinSubQueryContext)collection).GroupJoin; | |
49 | |
50 groupJoin.SqlQuery.From.Tables[0].Joins[0].JoinType = SqlQuery.JoinType.Inner; | |
51 groupJoin.SqlQuery.From.Tables[0].Joins[0].IsWeak = false; | |
52 } | |
53 | |
54 if (!newQuery) | |
55 { | |
56 context.Collection = new SubQueryContext(collection, sequence.SqlQuery, false); | |
57 return new SelectContext(buildInfo.Parent, resultSelector, sequence, context); | |
58 } | |
59 | |
60 if (!crossApply) | |
61 { | |
62 if (!leftJoin) | |
63 { | |
64 context.Collection = new SubQueryContext(collection, sequence.SqlQuery, true); | |
65 return new SelectContext(buildInfo.Parent, resultSelector, sequence, context); | |
66 } | |
67 else | |
68 { | |
69 var join = SqlQuery.OuterApply(sql); | |
70 sequence.SqlQuery.From.Tables[0].Joins.Add(join.JoinedTable); | |
71 context.Collection = new SubQueryContext(collection, sequence.SqlQuery, false); | |
72 | |
73 return new SelectContext(buildInfo.Parent, resultSelector, sequence, context); | |
74 } | |
75 } | |
76 | |
77 if (collection is TableBuilder.TableContext) | |
78 { | |
79 var table = (TableBuilder.TableContext)collection; | |
80 var join = table.SqlTable.TableArguments != null && table.SqlTable.TableArguments.Length > 0 ? | |
81 (leftJoin ? SqlQuery.OuterApply(sql) : SqlQuery.CrossApply(sql)) : | |
82 (leftJoin ? SqlQuery.LeftJoin (sql) : SqlQuery.InnerJoin (sql)); | |
83 | |
84 join.JoinedTable.Condition.Conditions.AddRange(sql.Where.SearchCondition.Conditions); | |
85 join.JoinedTable.CanConvertApply = false; | |
86 | |
87 sql.Where.SearchCondition.Conditions.Clear(); | |
88 | |
89 var collectionParent = collection.Parent as TableBuilder.TableContext; | |
90 | |
91 // Association. | |
92 // | |
93 if (collectionParent != null && collectionInfo.IsAssociationBuilt) | |
94 { | |
95 var ts = (SqlQuery.TableSource)new QueryVisitor().Find(sequence.SqlQuery.From, e => | |
96 { | |
97 if (e.ElementType == QueryElementType.TableSource) | |
98 { | |
99 var t = (SqlQuery.TableSource)e; | |
100 return t.Source == collectionParent.SqlTable; | |
101 } | |
102 | |
103 return false; | |
104 }); | |
105 | |
106 ts.Joins.Add(join.JoinedTable); | |
107 } | |
108 else | |
109 { | |
110 sequence.SqlQuery.From.Tables[0].Joins.Add(join.JoinedTable); | |
111 } | |
112 | |
113 context.Collection = new SubQueryContext(collection, sequence.SqlQuery, false); | |
114 return new SelectContext(buildInfo.Parent, resultSelector, sequence, context); | |
115 } | |
116 else | |
117 { | |
118 var join = leftJoin ? SqlQuery.OuterApply(sql) : SqlQuery.CrossApply(sql); | |
119 sequence.SqlQuery.From.Tables[0].Joins.Add(join.JoinedTable); | |
120 | |
121 context.Collection = new SubQueryContext(collection, sequence.SqlQuery, false); | |
122 return new SelectContext(buildInfo.Parent, resultSelector, sequence, context); | |
123 } | |
124 } | |
125 | |
126 protected override SequenceConvertInfo Convert( | |
127 ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo, ParameterExpression param) | |
128 { | |
129 return null; | |
130 } | |
131 | |
132 public class SelectManyContext : SelectContext | |
133 { | |
134 public SelectManyContext(IBuildContext parent, LambdaExpression lambda, IBuildContext sequence) | |
135 : base(parent, lambda, sequence) | |
136 { | |
137 } | |
138 | |
139 private IBuildContext _collection; | |
140 public IBuildContext Collection | |
141 { | |
142 get { return _collection; } | |
143 set | |
144 { | |
145 _collection = value; | |
146 _collection.Parent = this; | |
147 } | |
148 } | |
149 | |
150 public override Expression BuildExpression(Expression expression, int level) | |
151 { | |
152 if (expression == null) | |
153 return Collection.BuildExpression(expression, level); | |
154 | |
155 var root = expression.GetRootObject(); | |
156 | |
157 if (root == Lambda.Parameters[0]) | |
158 return base.BuildExpression(expression, level); | |
159 | |
160 return Collection.BuildExpression(expression, level); | |
161 } | |
162 | |
163 public override void BuildQuery<T>(Query<T> query, ParameterExpression queryParameter) | |
164 { | |
165 if (Collection == null) | |
166 base.BuildQuery(query, queryParameter); | |
167 | |
168 throw new InvalidOperationException(); | |
169 } | |
170 | |
171 public override SqlInfo[] ConvertToIndex(Expression expression, int level, ConvertFlags flags) | |
172 { | |
173 if (Collection != null) | |
174 { | |
175 if (expression == null) | |
176 return Collection.ConvertToIndex(expression, level, flags); | |
177 | |
178 var root = expression.GetRootObject(); | |
179 | |
180 if (root != Lambda.Parameters[0]) | |
181 return Collection.ConvertToIndex(expression, level, flags); | |
182 } | |
183 | |
184 return base.ConvertToIndex(expression, level, flags); | |
185 } | |
186 | |
187 /* | |
188 public override int ConvertToParentIndex(int index, IBuildContext context) | |
189 { | |
190 if (Collection == null) | |
191 return base.ConvertToParentIndex(index, context); | |
192 | |
193 throw new NotImplementedException(); | |
194 } | |
195 */ | |
196 | |
197 public override SqlInfo[] ConvertToSql(Expression expression, int level, ConvertFlags flags) | |
198 { | |
199 if (Collection != null) | |
200 { | |
201 if (expression == null) | |
202 return Collection.ConvertToSql(expression, level, flags); | |
203 | |
204 var root = expression.GetRootObject(); | |
205 | |
206 if (root != Lambda.Parameters[0]) | |
207 return Collection.ConvertToSql(expression, level, flags); | |
208 } | |
209 | |
210 return base.ConvertToSql(expression, level, flags); | |
211 } | |
212 | |
213 public override IBuildContext GetContext(Expression expression, int level, BuildInfo buildInfo) | |
214 { | |
215 if (Collection != null) | |
216 { | |
217 if (expression == null) | |
218 return Collection.GetContext(expression, level, buildInfo); | |
219 | |
220 var root = expression.GetRootObject(); | |
221 | |
222 if (root != Lambda.Parameters[0]) | |
223 return Collection.GetContext(expression, level, buildInfo); | |
224 } | |
225 | |
226 return base.GetContext(expression, level, buildInfo); | |
227 } | |
228 | |
229 public override IsExpressionResult IsExpression(Expression expression, int level, RequestFor requestFlag) | |
230 { | |
231 if (Collection != null) | |
232 { | |
233 if (expression == null) | |
234 return Collection.IsExpression(expression, level, requestFlag); | |
235 | |
236 var root = expression.GetRootObject(); | |
237 | |
238 if (root != Lambda.Parameters[0]) | |
239 return Collection.IsExpression(expression, level, requestFlag); | |
240 } | |
241 | |
242 return base.IsExpression(expression, level, requestFlag); | |
243 } | |
244 } | |
245 } | |
246 } |