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 } |
