annotate Source/Data/Linq/Builder/JoinBuilder.cs @ 1:8f65451dc28f

Исправлена проблема с фабрикой и выборкой нескольких объектов в linq выражении
author cin
date Fri, 28 Mar 2014 01:04:56 +0400
parents f990fcb411a9
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
1 using System;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
2 using System.Collections.Generic;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
3 using System.Linq;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
4 using System.Linq.Expressions;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
5
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
6 namespace BLToolkit.Data.Linq.Builder
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
7 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
8 using BLToolkit.Linq;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
9 using Data.Sql;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
10
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
11 class JoinBuilder : MethodCallBuilder
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
12 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
13 protected override bool CanBuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
14 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
15 if (!methodCall.IsQueryable("Join", "GroupJoin") || methodCall.Arguments.Count != 5)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
16 return false;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
17
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
18 var body = ((LambdaExpression)methodCall.Arguments[2].Unwrap()).Body.Unwrap();
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
19
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
20 if (body.NodeType == ExpressionType .MemberInit)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
21 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
22 var mi = (MemberInitExpression)body;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
23 bool throwExpr;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
24
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
25 if (mi.NewExpression.Arguments.Count > 0 || mi.Bindings.Count == 0)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
26 throwExpr = true;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
27 else
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
28 throwExpr = mi.Bindings.Any(b => b.BindingType != MemberBindingType.Assignment);
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
29
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
30 if (throwExpr)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
31 throw new NotSupportedException(string.Format("Explicit construction of entity type '{0}' in join is not allowed.", body.Type));
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
32 }
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
33
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
34 return true;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
35 }
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
36
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
37 protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
38 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
39 var isGroup = methodCall.Method.Name == "GroupJoin";
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
40 var outerContext = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0], buildInfo.SqlQuery));
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
41 var innerContext = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[1], new SqlQuery()));
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
42 var countContext = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[1], new SqlQuery()));
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
43
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
44 var context = new SubQueryContext(outerContext);
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
45 innerContext = isGroup ? new GroupJoinSubQueryContext(innerContext, methodCall) : new SubQueryContext(innerContext);
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
46 countContext = new SubQueryContext(countContext);
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
47
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
48 var join = isGroup ? innerContext.SqlQuery.WeakLeftJoin() : innerContext.SqlQuery.InnerJoin();
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
49 var sql = context.SqlQuery;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
50
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
51 sql.From.Tables[0].Joins.Add(join.JoinedTable);
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
52
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
53 var selector = (LambdaExpression)methodCall.Arguments[4].Unwrap();
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
54
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
55 context.SetAlias(selector.Parameters[0].Name);
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
56 innerContext.SetAlias(selector.Parameters[1].Name);
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
57
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
58 var outerKeyLambda = ((LambdaExpression)methodCall.Arguments[2].Unwrap());
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
59 var innerKeyLambda = ((LambdaExpression)methodCall.Arguments[3].Unwrap());
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
60
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
61 var outerKeySelector = outerKeyLambda.Body.Unwrap();
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
62 var innerKeySelector = innerKeyLambda.Body.Unwrap();
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
63
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
64 var outerParent = context. Parent;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
65 var innerParent = innerContext.Parent;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
66 var countParent = countContext.Parent;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
67
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
68 var outerKeyContext = new ExpressionContext(buildInfo.Parent, context, outerKeyLambda);
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
69 var innerKeyContext = new InnerKeyContext (buildInfo.Parent, innerContext, innerKeyLambda);
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
70 var countKeyContext = new ExpressionContext(buildInfo.Parent, countContext, innerKeyLambda);
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
71
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
72 // Process counter.
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
73 //
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
74 var counterSql = ((SubQueryContext)countContext).SqlQuery;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
75
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
76 // Make join and where for the counter.
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
77 //
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
78 if (outerKeySelector.NodeType == ExpressionType.New)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
79 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
80 var new1 = (NewExpression)outerKeySelector;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
81 var new2 = (NewExpression)innerKeySelector;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
82
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
83 for (var i = 0; i < new1.Arguments.Count; i++)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
84 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
85 var arg1 = new1.Arguments[i];
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
86 var arg2 = new2.Arguments[i];
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
87
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
88 BuildJoin(builder, join, outerKeyContext, arg1, innerKeyContext, arg2, countKeyContext, counterSql);
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
89 }
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
90 }
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
91 else if (outerKeySelector.NodeType == ExpressionType.MemberInit)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
92 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
93 var mi1 = (MemberInitExpression)outerKeySelector;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
94 var mi2 = (MemberInitExpression)innerKeySelector;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
95
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
96 for (var i = 0; i < mi1.Bindings.Count; i++)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
97 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
98 if (mi1.Bindings[i].Member != mi2.Bindings[i].Member)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
99 throw new LinqException(string.Format("List of member inits does not match for entity type '{0}'.", outerKeySelector.Type));
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
100
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
101 var arg1 = ((MemberAssignment)mi1.Bindings[i]).Expression;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
102 var arg2 = ((MemberAssignment)mi2.Bindings[i]).Expression;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
103
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
104 BuildJoin(builder, join, outerKeyContext, arg1, innerKeyContext, arg2, countKeyContext, counterSql);
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
105 }
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
106 }
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
107 else
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
108 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
109 BuildJoin(builder, join, outerKeyContext, outerKeySelector, innerKeyContext, innerKeySelector, countKeyContext, counterSql);
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
110 }
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
111
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
112 builder.ReplaceParent(outerKeyContext, outerParent);
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
113 builder.ReplaceParent(innerKeyContext, innerParent);
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
114 builder.ReplaceParent(countKeyContext, countParent);
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
115
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
116 if (isGroup)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
117 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
118 counterSql.ParentSql = sql;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
119 counterSql.Select.Columns.Clear();
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
120
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
121 var inner = (GroupJoinSubQueryContext)innerContext;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
122
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
123 inner.Join = join.JoinedTable;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
124 inner.CounterSql = counterSql;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
125 return new GroupJoinContext(
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
126 buildInfo.Parent, selector, context, inner, methodCall.Arguments[1], outerKeyLambda, innerKeyLambda);
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
127 }
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
128
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
129 return new JoinContext(buildInfo.Parent, selector, context, innerContext)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
130 #if DEBUG
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
131 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
132 MethodCall = methodCall
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
133 }
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
134 #endif
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
135 ;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
136 }
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
137
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
138 protected override SequenceConvertInfo Convert(
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
139 ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo, ParameterExpression param)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
140 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
141 return null;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
142 }
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
143
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
144 static void BuildJoin(
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
145 ExpressionBuilder builder,
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
146 SqlQuery.FromClause.Join join,
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
147 IBuildContext outerKeyContext, Expression outerKeySelector,
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
148 IBuildContext innerKeyContext, Expression innerKeySelector,
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
149 IBuildContext countKeyContext, SqlQuery countSql)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
150 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
151 var predicate = builder.ConvertObjectComparison(
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
152 ExpressionType.Equal,
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
153 outerKeyContext, outerKeySelector,
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
154 innerKeyContext, innerKeySelector);
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
155
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
156 if (predicate != null)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
157 join.JoinedTable.Condition.Conditions.Add(new SqlQuery.Condition(false, predicate));
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
158 else
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
159 join
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
160 .Expr(builder.ConvertToSql(outerKeyContext, outerKeySelector, false)).Equal
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
161 .Expr(builder.ConvertToSql(innerKeyContext, innerKeySelector, false));
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
162
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
163 predicate = builder.ConvertObjectComparison(
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
164 ExpressionType.Equal,
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
165 outerKeyContext, outerKeySelector,
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
166 countKeyContext, innerKeySelector);
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
167
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
168 if (predicate != null)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
169 countSql.Where.SearchCondition.Conditions.Add(new SqlQuery.Condition(false, predicate));
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
170 else
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
171 countSql.Where
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
172 .Expr(builder.ConvertToSql(outerKeyContext, outerKeySelector, false)).Equal
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
173 .Expr(builder.ConvertToSql(countKeyContext, innerKeySelector, false));
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
174 }
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
175
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
176 class InnerKeyContext : ExpressionContext
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
177 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
178 public InnerKeyContext(IBuildContext parent, IBuildContext sequence, LambdaExpression lambda)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
179 : base(parent, sequence, lambda)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
180 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
181 }
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
182
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
183 public override SqlInfo[] ConvertToSql(Expression expression, int level, ConvertFlags flags)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
184 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
185 return base
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
186 .ConvertToSql(expression, level, flags)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
187 .Select(idx =>
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
188 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
189 var n = SqlQuery.Select.Add(idx.Sql);
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
190
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
191 return new SqlInfo(idx.Members)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
192 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
193 Sql = SqlQuery.Select.Columns[n],
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
194 Index = n
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
195 };
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
196 })
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
197 .ToArray();
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
198 }
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
199 }
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
200
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
201 internal class JoinContext : SelectContext
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
202 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
203 public JoinContext(IBuildContext parent, LambdaExpression lambda, IBuildContext outerContext, IBuildContext innerContext)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
204 : base(parent, lambda, outerContext, innerContext)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
205 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
206 }
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
207 }
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
208
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
209 internal class GroupJoinContext : JoinContext
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
210 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
211 public GroupJoinContext(
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
212 IBuildContext parent,
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
213 LambdaExpression lambda,
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
214 IBuildContext outerContext,
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
215 GroupJoinSubQueryContext innerContext,
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
216 Expression innerExpression,
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
217 LambdaExpression outerKeyLambda,
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
218 LambdaExpression innerKeyLambda)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
219 : base(parent, lambda, outerContext, innerContext)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
220 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
221 _innerExpression = innerExpression;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
222 _outerKeyLambda = outerKeyLambda;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
223 _innerKeyLambda = innerKeyLambda;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
224
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
225 innerContext.GroupJoin = this;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
226 }
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
227
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
228 readonly Expression _innerExpression;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
229 readonly LambdaExpression _outerKeyLambda;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
230 readonly LambdaExpression _innerKeyLambda;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
231 private Expression _groupExpression;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
232
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
233 interface IGroupJoinHelper
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
234 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
235 Expression GetGroupJoin(GroupJoinContext context);
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
236 }
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
237
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
238 class GroupJoinHelper<TKey,TElement> : IGroupJoinHelper
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
239 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
240 public Expression GetGroupJoin(GroupJoinContext context)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
241 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
242 // Convert outer condition.
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
243 //
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
244 var outerParam = Expression.Parameter(context._outerKeyLambda.Body.Type, "o");
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
245 var outerKey = context._outerKeyLambda.Body.Convert(
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
246 e => e == context._outerKeyLambda.Parameters[0] ? context.Lambda.Parameters[0] : e);
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
247
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
248 outerKey = context.Builder.BuildExpression(context, outerKey);
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
249
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
250 // Convert inner condition.
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
251 //
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
252 var parameters = context.Builder.CurrentSqlParameters
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
253 .Select((p,i) => new { p, i })
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
254 .ToDictionary(_ => _.p.Expression, _ => _.i);
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
255 var paramArray = Expression.Parameter(typeof(object[]), "ps");
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
256
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
257 var innerKey = context._innerKeyLambda.Body.Convert(e =>
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
258 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
259 int idx;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
260
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
261 if (parameters.TryGetValue(e, out idx))
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
262 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
263 return
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
264 Expression.Convert(
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
265 Expression.ArrayIndex(paramArray, Expression.Constant(idx)),
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
266 e.Type);
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
267 }
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
268
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
269 return e;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
270 });
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
271
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
272 // Item reader.
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
273 //
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
274 // ReSharper disable AssignNullToNotNullAttribute
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
275
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
276 var expr = Expression.Call(
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
277 null,
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
278 ReflectionHelper.Expressor<object>.MethodExpressor(_ => Queryable.Where(null, (Expression<Func<TElement,bool>>)null)),
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
279 context._innerExpression,
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
280 Expression.Lambda<Func<TElement,bool>>(
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
281 Expression.Equal(innerKey, outerParam),
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
282 new[] { context._innerKeyLambda.Parameters[0] }));
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
283
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
284 // ReSharper restore AssignNullToNotNullAttribute
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
285
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
286 var lambda = Expression.Lambda<Func<IDataContext,TKey,object[],IQueryable<TElement>>>(
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
287 Expression.Convert(expr, typeof(IQueryable<TElement>)),
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
288 Expression.Parameter(typeof(IDataContext), "ctx"),
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
289 outerParam,
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
290 paramArray);
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
291
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
292 var itemReader = CompiledQuery.Compile(lambda);
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
293
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
294 return Expression.Call(
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
295 null,
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
296 ReflectionHelper.Expressor<object>.MethodExpressor(_ => GetGrouping(null, null, default(TKey), null)),
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
297 new[]
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
298 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
299 ExpressionBuilder.ContextParam,
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
300 Expression.Constant(context.Builder.CurrentSqlParameters),
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
301 outerKey,
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
302 Expression.Constant(itemReader),
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
303 });
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
304 }
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
305
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
306 static IEnumerable<TElement> GetGrouping(
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
307 QueryContext context,
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
308 List<ParameterAccessor> parameterAccessor,
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
309 TKey key,
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
310 Func<IDataContext,TKey,object[],IQueryable<TElement>> itemReader)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
311 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
312 return new GroupByBuilder.GroupByContext.Grouping<TKey,TElement>(key, context, parameterAccessor, itemReader);
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
313 }
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
314 }
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
315
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
316 public override Expression BuildExpression(Expression expression, int level)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
317 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
318 if (expression == Lambda.Parameters[1])
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
319 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
320 if (_groupExpression == null)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
321 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
322 var gtype = typeof(GroupJoinHelper<,>).MakeGenericType(
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
323 _innerKeyLambda.Body.Type,
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
324 _innerKeyLambda.Parameters[0].Type);
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
325
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
326 var helper = (IGroupJoinHelper)Activator.CreateInstance(gtype);
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
327
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
328 _groupExpression = helper.GetGroupJoin(this);
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
329 }
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
330
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
331 return _groupExpression;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
332 }
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
333
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
334 return base.BuildExpression(expression, level);
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
335 }
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
336 }
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
337
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
338 internal class GroupJoinSubQueryContext : SubQueryContext
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
339 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
340 //readonly MethodCallExpression _methodCall;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
341
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
342 public SqlQuery.JoinedTable Join;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
343 public SqlQuery CounterSql;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
344 public GroupJoinContext GroupJoin;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
345
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
346 public GroupJoinSubQueryContext(IBuildContext subQuery, MethodCallExpression methodCall)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
347 : base(subQuery)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
348 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
349 //_methodCall = methodCall;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
350 }
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
351
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
352 public override IBuildContext GetContext(Expression expression, int level, BuildInfo buildInfo)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
353 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
354 if (expression == null)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
355 return this;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
356
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
357 return base.GetContext(expression, level, buildInfo);
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
358 }
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
359
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
360 Expression _counterExpression;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
361 SqlInfo[] _counterInfo;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
362
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
363 public override SqlInfo[] ConvertToIndex(Expression expression, int level, ConvertFlags flags)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
364 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
365 if (expression != null && expression == _counterExpression)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
366 return _counterInfo ?? (_counterInfo = new[]
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
367 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
368 new SqlInfo
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
369 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
370 Query = CounterSql.ParentSql,
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
371 Index = CounterSql.ParentSql.Select.Add(CounterSql),
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
372 Sql = CounterSql
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
373 }
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
374 });
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
375
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
376 return base.ConvertToIndex(expression, level, flags);
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
377 }
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
378
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
379 public override IsExpressionResult IsExpression(Expression expression, int level, RequestFor testFlag)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
380 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
381 if (testFlag == RequestFor.GroupJoin && expression == null)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
382 return IsExpressionResult.True;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
383
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
384 return base.IsExpression(expression, level, testFlag);
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
385 }
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
386
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
387 public SqlQuery GetCounter(Expression expr)
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
388 {
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
389 Join.IsWeak = true;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
390
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
391 _counterExpression = expr;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
392
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
393 return CounterSql;
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
394 }
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
395 }
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
396 }
f990fcb411a9 Копия текущей версии из github
cin
parents:
diff changeset
397 }