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 }