comparison Source/Data/Linq/Builder/InsertBuilder.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.Linq;
3 using System.Linq.Expressions;
4
5 namespace BLToolkit.Data.Linq.Builder
6 {
7 using BLToolkit.Linq;
8 using Data.Sql;
9
10 class InsertBuilder : MethodCallBuilder
11 {
12 #region InsertBuilder
13
14 protected override bool CanBuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
15 {
16 return methodCall.IsQueryable("Insert", "InsertWithIdentity");
17 }
18
19 protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
20 {
21 var sequence = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));
22
23 var isSubQuery = sequence.SqlQuery.Select.IsDistinct;
24
25 if (isSubQuery)
26 sequence = new SubQueryContext(sequence);
27
28 switch (methodCall.Arguments.Count)
29 {
30 case 1 :
31 // static int Insert<T> (this IValueInsertable<T> source)
32 // static int Insert<TSource,TTarget>(this ISelectInsertable<TSource,TTarget> source)
33 {
34 foreach (var item in sequence.SqlQuery.Insert.Items)
35 sequence.SqlQuery.Select.Expr(item.Expression);
36 break;
37 }
38
39 case 2 : // static int Insert<T>(this Table<T> target, Expression<Func<T>> setter)
40 {
41 UpdateBuilder.BuildSetter(
42 builder,
43 buildInfo,
44 (LambdaExpression)methodCall.Arguments[1].Unwrap(),
45 sequence,
46 sequence.SqlQuery.Insert.Items,
47 sequence);
48
49 sequence.SqlQuery.Insert.Into = ((TableBuilder.TableContext)sequence).SqlTable;
50 sequence.SqlQuery.From.Tables.Clear();
51
52 break;
53 }
54
55 case 3 : // static int Insert<TSource,TTarget>(this IQueryable<TSource> source, Table<TTarget> target, Expression<Func<TSource,TTarget>> setter)
56 {
57 var into = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[1], new SqlQuery()));
58
59 UpdateBuilder.BuildSetter(
60 builder,
61 buildInfo,
62 (LambdaExpression)methodCall.Arguments[2].Unwrap(),
63 into,
64 sequence.SqlQuery.Insert.Items,
65 sequence);
66
67 sequence.SqlQuery.Select.Columns.Clear();
68
69 foreach (var item in sequence.SqlQuery.Insert.Items)
70 sequence.SqlQuery.Select.Columns.Add(new SqlQuery.Column(sequence.SqlQuery, item.Expression));
71
72 sequence.SqlQuery.Insert.Into = ((TableBuilder.TableContext)into).SqlTable;
73
74 break;
75 }
76 }
77
78 var insert = sequence.SqlQuery.Insert;
79
80 var q = insert.Into.Fields.Values.Cast<ISqlExpression>().Except(insert.Items.Select(e => e.Column))
81 .OfType<SqlField>()
82 .Where(f => f.IsIdentity);
83
84 foreach (var field in q)
85 {
86 var expr = builder.SqlProvider.GetIdentityExpression(insert.Into, field, false);
87
88 if (expr != null)
89 {
90 insert.Items.Insert(0, new SqlQuery.SetExpression(field, expr));
91
92 if (methodCall.Arguments.Count == 3)
93 {
94 sequence.SqlQuery.Select.Columns.Insert(0, new SqlQuery.Column(sequence.SqlQuery, insert.Items[0].Expression));
95 }
96 }
97 }
98
99 sequence.SqlQuery.QueryType = QueryType.Insert;
100 sequence.SqlQuery.Insert.WithIdentity = methodCall.Method.Name == "InsertWithIdentity";
101
102 return new InsertContext(buildInfo.Parent, sequence, sequence.SqlQuery.Insert.WithIdentity);
103 }
104
105 protected override SequenceConvertInfo Convert(
106 ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo, ParameterExpression param)
107 {
108 return null;
109 }
110
111 #endregion
112
113 #region InsertContext
114
115 class InsertContext : SequenceContextBase
116 {
117 public InsertContext(IBuildContext parent, IBuildContext sequence, bool insertWithIdentity)
118 : base(parent, sequence, null)
119 {
120 _insertWithIdentity = insertWithIdentity;
121 }
122
123 readonly bool _insertWithIdentity;
124
125 public override void BuildQuery<T>(Query<T> query, ParameterExpression queryParameter)
126 {
127 if (_insertWithIdentity) query.SetScalarQuery<object>();
128 else query.SetNonQueryQuery();
129 }
130
131 public override Expression BuildExpression(Expression expression, int level)
132 {
133 throw new InvalidOperationException();
134 }
135
136 public override SqlInfo[] ConvertToSql(Expression expression, int level, ConvertFlags flags)
137 {
138 throw new InvalidOperationException();
139 }
140
141 public override SqlInfo[] ConvertToIndex(Expression expression, int level, ConvertFlags flags)
142 {
143 throw new InvalidOperationException();
144 }
145
146 public override IsExpressionResult IsExpression(Expression expression, int level, RequestFor requestFlag)
147 {
148 throw new InvalidOperationException();
149 }
150
151 public override IBuildContext GetContext(Expression expression, int level, BuildInfo buildInfo)
152 {
153 throw new InvalidOperationException();
154 }
155 }
156
157 #endregion
158
159 #region Into
160
161 internal class Into : MethodCallBuilder
162 {
163 protected override bool CanBuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
164 {
165 return methodCall.IsQueryable("Into");
166 }
167
168 protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
169 {
170 var source = methodCall.Arguments[0].Unwrap();
171 var into = methodCall.Arguments[1].Unwrap();
172
173 IBuildContext sequence;
174
175 // static IValueInsertable<T> Into<T>(this IDataContext dataContext, Table<T> target)
176 //
177 if (source.NodeType == ExpressionType.Constant && ((ConstantExpression)source).Value == null)
178 {
179 sequence = builder.BuildSequence(new BuildInfo((IBuildContext)null, into, new SqlQuery()));
180
181 if (sequence.SqlQuery.Select.IsDistinct)
182 sequence = new SubQueryContext(sequence);
183
184 sequence.SqlQuery.Insert.Into = ((TableBuilder.TableContext)sequence).SqlTable;
185 sequence.SqlQuery.From.Tables.Clear();
186 }
187 // static ISelectInsertable<TSource,TTarget> Into<TSource,TTarget>(this IQueryable<TSource> source, Table<TTarget> target)
188 //
189 else
190 {
191 sequence = builder.BuildSequence(new BuildInfo(buildInfo, source));
192
193 if (sequence.SqlQuery.Select.IsDistinct)
194 sequence = new SubQueryContext(sequence);
195
196 var tbl = builder.BuildSequence(new BuildInfo((IBuildContext)null, into, new SqlQuery()));
197 sequence.SqlQuery.Insert.Into = ((TableBuilder.TableContext)tbl).SqlTable;
198 }
199
200 sequence.SqlQuery.Select.Columns.Clear();
201
202 return sequence;
203 }
204
205 protected override SequenceConvertInfo Convert(
206 ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo, ParameterExpression param)
207 {
208 return null;
209 }
210 }
211
212 #endregion
213
214 #region Value
215
216 internal class Value : MethodCallBuilder
217 {
218 protected override bool CanBuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
219 {
220 return methodCall.IsQueryable("Value");
221 }
222
223 protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
224 {
225 var sequence = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));
226 var extract = (LambdaExpression)methodCall.Arguments[1].Unwrap();
227 var update = methodCall.Arguments[2].Unwrap();
228
229 if (sequence.SqlQuery.Insert.Into == null)
230 {
231 sequence.SqlQuery.Insert.Into = (SqlTable)sequence.SqlQuery.From.Tables[0].Source;
232 sequence.SqlQuery.From.Tables.Clear();
233 }
234
235 if (update.NodeType == ExpressionType.Lambda)
236 UpdateBuilder.ParseSet(
237 builder,
238 buildInfo,
239 extract,
240 (LambdaExpression)update,
241 sequence,
242 sequence.SqlQuery.Insert.Into,
243 sequence.SqlQuery.Insert.Items);
244 else
245 UpdateBuilder.ParseSet(
246 builder,
247 buildInfo,
248 extract,
249 update,
250 sequence,
251 sequence.SqlQuery.Insert.Items);
252
253 return sequence;
254 }
255
256 protected override SequenceConvertInfo Convert(
257 ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo, ParameterExpression param)
258 {
259 return null;
260 }
261 }
262
263 #endregion
264 }
265 }