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 }