Mercurial > pub > bltoolkit
comparison Source/Data/Linq/CompiledQuery.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 | |
7 { | |
8 using BLToolkit.Linq; | |
9 using Reflection; | |
10 | |
11 /// <summary> | |
12 /// Provides for compilation and caching of queries for reuse. | |
13 /// </summary> | |
14 public class CompiledQuery | |
15 { | |
16 protected CompiledQuery(LambdaExpression query) | |
17 { | |
18 _query = query; | |
19 } | |
20 | |
21 readonly object _sync = new object(); | |
22 readonly LambdaExpression _query; | |
23 volatile Func<object[],object> _compiledQuery; | |
24 | |
25 TResult ExecuteQuery<TResult>(params object[] args) | |
26 { | |
27 if (_compiledQuery == null) | |
28 lock (_sync) | |
29 if (_compiledQuery == null) | |
30 _compiledQuery = CompileQuery(_query); | |
31 | |
32 return (TResult)_compiledQuery(args); | |
33 } | |
34 | |
35 private interface ITableHelper | |
36 { | |
37 Expression CallTable(LambdaExpression query, Expression expr, ParameterExpression ps, bool isQueriable); | |
38 } | |
39 | |
40 internal class TableHelper<T> : ITableHelper | |
41 { | |
42 public Expression CallTable(LambdaExpression query, Expression expr, ParameterExpression ps, bool isQueriable) | |
43 { | |
44 var table = new CompiledTable<T>(query, expr); | |
45 | |
46 return Expression.Call( | |
47 Expression.Constant(table), | |
48 isQueriable ? | |
49 ReflectionHelper.Expressor<CompiledTable<T>>.MethodExpressor(t => t.Create (null)) : | |
50 ReflectionHelper.Expressor<CompiledTable<T>>.MethodExpressor(t => t.Execute(null)), | |
51 ps); | |
52 } | |
53 } | |
54 | |
55 static Func<object[],object> CompileQuery(LambdaExpression query) | |
56 { | |
57 var ps = Expression.Parameter(typeof(object[]), "ps"); | |
58 | |
59 var info = query.Body.Convert(pi => | |
60 { | |
61 switch (pi.NodeType) | |
62 { | |
63 case ExpressionType.Parameter : | |
64 { | |
65 var idx = query.Parameters.IndexOf((ParameterExpression)pi); | |
66 | |
67 if (idx >= 0) | |
68 return Expression.Convert(Expression.ArrayIndex(ps, Expression.Constant(idx)), pi.Type); | |
69 | |
70 break; | |
71 } | |
72 | |
73 case ExpressionType.Call : | |
74 { | |
75 var expr = (MethodCallExpression)pi; | |
76 | |
77 if (expr.IsQueryable()) | |
78 { | |
79 var qtype = TypeHelper.GetGenericType( | |
80 TypeHelper.IsSameOrParent(typeof(IQueryable), expr.Type) ? | |
81 typeof(IQueryable<>) : | |
82 typeof(IEnumerable<>), | |
83 expr.Type); | |
84 | |
85 var helper = (ITableHelper)Activator.CreateInstance( | |
86 typeof(TableHelper<>).MakeGenericType(qtype == null ? expr.Type : qtype.GetGenericArguments()[0])); | |
87 | |
88 return helper.CallTable(query, expr, ps, qtype != null); | |
89 } | |
90 | |
91 if (expr.Method.Name == "GetTable" && expr.Method.DeclaringType == typeof(Extensions)) | |
92 goto case ExpressionType.MemberAccess; | |
93 } | |
94 | |
95 break; | |
96 | |
97 case ExpressionType.MemberAccess : | |
98 if (pi.Type.IsGenericType && pi.Type.GetGenericTypeDefinition() == typeof(Table<>)) | |
99 { | |
100 var helper = (ITableHelper)Activator | |
101 .CreateInstance(typeof(TableHelper<>) | |
102 .MakeGenericType(pi.Type.GetGenericArguments()[0])); | |
103 return helper.CallTable(query, pi, ps, true); | |
104 } | |
105 | |
106 break; | |
107 } | |
108 | |
109 return pi; | |
110 }); | |
111 | |
112 return Expression.Lambda<Func<object[],object>>(Expression.Convert(info, typeof(object)), ps).Compile(); | |
113 } | |
114 | |
115 #region Invoke | |
116 | |
117 public TResult Invoke<TDC,TResult>(TDC dataContext) | |
118 { | |
119 return ExecuteQuery<TResult>(dataContext); | |
120 } | |
121 | |
122 public TResult Invoke<TDC,T1,TResult>(TDC dataContext, T1 arg1) | |
123 { | |
124 return ExecuteQuery<TResult>(dataContext, arg1); | |
125 } | |
126 | |
127 public TResult Invoke<TDC,T1,T2,TResult>(TDC dataContext, T1 arg1, T2 arg2) | |
128 { | |
129 return ExecuteQuery<TResult>(dataContext, arg1, arg2); | |
130 } | |
131 | |
132 public TResult Invoke<TDC,T1,T2,T3,TResult>(TDC dataContext, T1 arg1, T2 arg2, T3 arg3) | |
133 { | |
134 return ExecuteQuery<TResult>(dataContext, arg1, arg2, arg3); | |
135 } | |
136 | |
137 public TResult Invoke<TDC,T1,T2,T3,T4,TResult>(TDC dataContext, T1 arg1, T2 arg2, T3 arg3, T4 arg4) | |
138 { | |
139 return ExecuteQuery<TResult>(dataContext, arg1, arg2, arg3, arg4); | |
140 } | |
141 | |
142 public TResult Invoke<TDC,T1,T2,T3,T4,T5,TResult>(TDC dataContext, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) | |
143 { | |
144 return ExecuteQuery<TResult>(dataContext, arg1, arg2, arg3, arg4, arg5); | |
145 } | |
146 | |
147 #endregion | |
148 | |
149 #region Compile | |
150 | |
151 /// <summary> | |
152 /// Compiles the query. | |
153 /// </summary> | |
154 /// <returns> | |
155 /// A generic delegate that represents the compiled query. | |
156 /// </returns> | |
157 /// <param name="query"> | |
158 /// The query expression to be compiled. | |
159 /// </param> | |
160 /// <typeparam name="TDC "> | |
161 /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. | |
162 /// </typeparam> | |
163 /// <typeparam name="TResult"> | |
164 /// Returned type of the delegate returned by the method. | |
165 /// </typeparam> | |
166 public static Func<TDC,TResult> Compile<TDC,TResult>( | |
167 [JetBrains.Annotations.NotNull] Expression<Func<TDC,TResult>> query) | |
168 where TDC : IDataContext | |
169 { | |
170 if (query == null) throw new ArgumentNullException("query"); | |
171 return new CompiledQuery(query).Invoke<TDC,TResult>; | |
172 } | |
173 | |
174 /// <summary> | |
175 /// Compiles the query. | |
176 /// </summary> | |
177 /// <returns> | |
178 /// A generic delegate that represents the compiled query. | |
179 /// </returns> | |
180 /// <param name="query"> | |
181 /// The query expression to be compiled. | |
182 /// </param> | |
183 /// <typeparam name="TDC"> | |
184 /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. | |
185 /// </typeparam> | |
186 /// <typeparam name="TArg1"> | |
187 /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. | |
188 /// </typeparam> | |
189 /// <typeparam name="TResult"> | |
190 /// Returned type of the delegate returned by the method. | |
191 /// </typeparam> | |
192 public static Func<TDC,TArg1,TResult> Compile<TDC,TArg1,TResult>( | |
193 [JetBrains.Annotations.NotNull] Expression<Func<TDC,TArg1,TResult>> query) | |
194 where TDC : IDataContext | |
195 { | |
196 if (query == null) throw new ArgumentNullException("query"); | |
197 return new CompiledQuery(query).Invoke<TDC,TArg1,TResult>; | |
198 } | |
199 | |
200 /// <summary> | |
201 /// Compiles the query. | |
202 /// </summary> | |
203 /// <returns> | |
204 /// A generic delegate that represents the compiled query. | |
205 /// </returns> | |
206 /// <param name="query"> | |
207 /// The query expression to be compiled. | |
208 /// </param> | |
209 /// <typeparam name="TDC "> | |
210 /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. | |
211 /// </typeparam> | |
212 /// <typeparam name="TArg1"> | |
213 /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. | |
214 /// </typeparam> | |
215 /// <typeparam name="TArg2"> | |
216 /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. | |
217 /// </typeparam> | |
218 /// <typeparam name="TResult"> | |
219 /// Returned type of the delegate returned by the method. | |
220 /// </typeparam> | |
221 public static Func<TDC,TArg1,TArg2,TResult> Compile<TDC,TArg1,TArg2,TResult>( | |
222 [JetBrains.Annotations.NotNull] Expression<Func<TDC,TArg1,TArg2,TResult>> query) | |
223 where TDC : IDataContext | |
224 { | |
225 if (query == null) throw new ArgumentNullException("query"); | |
226 return new CompiledQuery(query).Invoke<TDC,TArg1,TArg2,TResult>; | |
227 } | |
228 | |
229 /// <summary> | |
230 /// Compiles the query. | |
231 /// </summary> | |
232 /// <returns> | |
233 /// A generic delegate that represents the compiled query. | |
234 /// </returns> | |
235 /// <param name="query"> | |
236 /// The query expression to be compiled. | |
237 /// </param> | |
238 /// <typeparam name="TDC "> | |
239 /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. | |
240 /// </typeparam> | |
241 /// <typeparam name="TArg1"> | |
242 /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. | |
243 /// </typeparam> | |
244 /// <typeparam name="TArg2"> | |
245 /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. | |
246 /// </typeparam> | |
247 /// <typeparam name="TArg3"> | |
248 /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. | |
249 /// </typeparam> | |
250 /// <typeparam name="TResult"> | |
251 /// Returned type of the delegate returned by the method. | |
252 /// </typeparam> | |
253 public static Func<TDC,TArg1,TArg2,TArg3,TResult> Compile<TDC,TArg1,TArg2,TArg3,TResult>( | |
254 [JetBrains.Annotations.NotNull] Expression<Func<TDC,TArg1,TArg2,TArg3,TResult>> query) | |
255 where TDC : IDataContext | |
256 { | |
257 if (query == null) throw new ArgumentNullException("query"); | |
258 return new CompiledQuery(query).Invoke<TDC,TArg1,TArg2,TArg3,TResult>; | |
259 } | |
260 | |
261 /// <summary> | |
262 /// Compiles the query. | |
263 /// </summary> | |
264 /// <returns> | |
265 /// A generic delegate that represents the compiled query. | |
266 /// </returns> | |
267 /// <param name="query"> | |
268 /// The query expression to be compiled. | |
269 /// </param> | |
270 /// <typeparam name="TDC "> | |
271 /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. | |
272 /// </typeparam> | |
273 /// <typeparam name="TArg1"> | |
274 /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. | |
275 /// </typeparam> | |
276 /// <typeparam name="TArg2"> | |
277 /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. | |
278 /// </typeparam> | |
279 /// <typeparam name="TArg3"> | |
280 /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. | |
281 /// </typeparam> | |
282 /// <typeparam name="TArg4"> | |
283 /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. | |
284 /// </typeparam> | |
285 /// <typeparam name="TResult"> | |
286 /// Returned type of the delegate returned by the method. | |
287 /// </typeparam> | |
288 public static Func<TDC,TArg1,TArg2,TArg3,TArg4,TResult> Compile<TDC,TArg1,TArg2,TArg3,TArg4,TResult>( | |
289 [JetBrains.Annotations.NotNull] Expression<Func<TDC,TArg1,TArg2,TArg3,TArg4,TResult>> query) | |
290 where TDC : IDataContext | |
291 { | |
292 if (query == null) throw new ArgumentNullException("query"); | |
293 return new CompiledQuery(query).Invoke<TDC,TArg1,TArg2,TArg3,TArg4,TResult>; | |
294 } | |
295 | |
296 /// <summary> | |
297 /// Compiles the query. | |
298 /// </summary> | |
299 /// <returns> | |
300 /// A generic delegate that represents the compiled query. | |
301 /// </returns> | |
302 /// <param name="query"> | |
303 /// The query expression to be compiled. | |
304 /// </param> | |
305 /// <typeparam name="TDC "> | |
306 /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. | |
307 /// </typeparam> | |
308 /// <typeparam name="TArg1"> | |
309 /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. | |
310 /// </typeparam> | |
311 /// <typeparam name="TArg2"> | |
312 /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. | |
313 /// </typeparam> | |
314 /// <typeparam name="TArg3"> | |
315 /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. | |
316 /// </typeparam> | |
317 /// <typeparam name="TArg4"> | |
318 /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. | |
319 /// </typeparam> | |
320 /// <typeparam name="TArg5"> | |
321 /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. | |
322 /// </typeparam> | |
323 /// <typeparam name="TResult"> | |
324 /// Returned type of the delegate returned by the method. | |
325 /// </typeparam> | |
326 public static Func<TDC,TArg1,TArg2,TArg3,TArg4,TArg5,TResult> Compile<TDC,TArg1,TArg2,TArg3,TArg4,TArg5,TResult>( | |
327 [JetBrains.Annotations.NotNull] Expression<Func<TDC,TArg1,TArg2,TArg3,TArg4,TArg5,TResult>> query) | |
328 where TDC : IDataContext | |
329 { | |
330 if (query == null) throw new ArgumentNullException("query"); | |
331 return new CompiledQuery(query).Invoke<TDC,TArg1,TArg2,TArg3,TArg4,TArg5,TResult>; | |
332 } | |
333 | |
334 #endregion | |
335 } | |
336 } |