Mercurial > pub > bltoolkit
view Source/Data/Linq/CompiledQuery.cs @ 4:f757da6161a1
!bug 100 + 2h fixed gregression
author | cin |
---|---|
date | Sun, 24 Aug 2014 17:57:42 +0400 |
parents | f990fcb411a9 |
children |
line wrap: on
line source
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; namespace BLToolkit.Data.Linq { using BLToolkit.Linq; using Reflection; /// <summary> /// Provides for compilation and caching of queries for reuse. /// </summary> public class CompiledQuery { protected CompiledQuery(LambdaExpression query) { _query = query; } readonly object _sync = new object(); readonly LambdaExpression _query; volatile Func<object[],object> _compiledQuery; TResult ExecuteQuery<TResult>(params object[] args) { if (_compiledQuery == null) lock (_sync) if (_compiledQuery == null) _compiledQuery = CompileQuery(_query); return (TResult)_compiledQuery(args); } private interface ITableHelper { Expression CallTable(LambdaExpression query, Expression expr, ParameterExpression ps, bool isQueriable); } internal class TableHelper<T> : ITableHelper { public Expression CallTable(LambdaExpression query, Expression expr, ParameterExpression ps, bool isQueriable) { var table = new CompiledTable<T>(query, expr); return Expression.Call( Expression.Constant(table), isQueriable ? ReflectionHelper.Expressor<CompiledTable<T>>.MethodExpressor(t => t.Create (null)) : ReflectionHelper.Expressor<CompiledTable<T>>.MethodExpressor(t => t.Execute(null)), ps); } } static Func<object[],object> CompileQuery(LambdaExpression query) { var ps = Expression.Parameter(typeof(object[]), "ps"); var info = query.Body.Convert(pi => { switch (pi.NodeType) { case ExpressionType.Parameter : { var idx = query.Parameters.IndexOf((ParameterExpression)pi); if (idx >= 0) return Expression.Convert(Expression.ArrayIndex(ps, Expression.Constant(idx)), pi.Type); break; } case ExpressionType.Call : { var expr = (MethodCallExpression)pi; if (expr.IsQueryable()) { var qtype = TypeHelper.GetGenericType( TypeHelper.IsSameOrParent(typeof(IQueryable), expr.Type) ? typeof(IQueryable<>) : typeof(IEnumerable<>), expr.Type); var helper = (ITableHelper)Activator.CreateInstance( typeof(TableHelper<>).MakeGenericType(qtype == null ? expr.Type : qtype.GetGenericArguments()[0])); return helper.CallTable(query, expr, ps, qtype != null); } if (expr.Method.Name == "GetTable" && expr.Method.DeclaringType == typeof(Extensions)) goto case ExpressionType.MemberAccess; } break; case ExpressionType.MemberAccess : if (pi.Type.IsGenericType && pi.Type.GetGenericTypeDefinition() == typeof(Table<>)) { var helper = (ITableHelper)Activator .CreateInstance(typeof(TableHelper<>) .MakeGenericType(pi.Type.GetGenericArguments()[0])); return helper.CallTable(query, pi, ps, true); } break; } return pi; }); return Expression.Lambda<Func<object[],object>>(Expression.Convert(info, typeof(object)), ps).Compile(); } #region Invoke public TResult Invoke<TDC,TResult>(TDC dataContext) { return ExecuteQuery<TResult>(dataContext); } public TResult Invoke<TDC,T1,TResult>(TDC dataContext, T1 arg1) { return ExecuteQuery<TResult>(dataContext, arg1); } public TResult Invoke<TDC,T1,T2,TResult>(TDC dataContext, T1 arg1, T2 arg2) { return ExecuteQuery<TResult>(dataContext, arg1, arg2); } public TResult Invoke<TDC,T1,T2,T3,TResult>(TDC dataContext, T1 arg1, T2 arg2, T3 arg3) { return ExecuteQuery<TResult>(dataContext, arg1, arg2, arg3); } public TResult Invoke<TDC,T1,T2,T3,T4,TResult>(TDC dataContext, T1 arg1, T2 arg2, T3 arg3, T4 arg4) { return ExecuteQuery<TResult>(dataContext, arg1, arg2, arg3, arg4); } public TResult Invoke<TDC,T1,T2,T3,T4,T5,TResult>(TDC dataContext, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) { return ExecuteQuery<TResult>(dataContext, arg1, arg2, arg3, arg4, arg5); } #endregion #region Compile /// <summary> /// Compiles the query. /// </summary> /// <returns> /// A generic delegate that represents the compiled query. /// </returns> /// <param name="query"> /// The query expression to be compiled. /// </param> /// <typeparam name="TDC "> /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. /// </typeparam> /// <typeparam name="TResult"> /// Returned type of the delegate returned by the method. /// </typeparam> public static Func<TDC,TResult> Compile<TDC,TResult>( [JetBrains.Annotations.NotNull] Expression<Func<TDC,TResult>> query) where TDC : IDataContext { if (query == null) throw new ArgumentNullException("query"); return new CompiledQuery(query).Invoke<TDC,TResult>; } /// <summary> /// Compiles the query. /// </summary> /// <returns> /// A generic delegate that represents the compiled query. /// </returns> /// <param name="query"> /// The query expression to be compiled. /// </param> /// <typeparam name="TDC"> /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. /// </typeparam> /// <typeparam name="TArg1"> /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. /// </typeparam> /// <typeparam name="TResult"> /// Returned type of the delegate returned by the method. /// </typeparam> public static Func<TDC,TArg1,TResult> Compile<TDC,TArg1,TResult>( [JetBrains.Annotations.NotNull] Expression<Func<TDC,TArg1,TResult>> query) where TDC : IDataContext { if (query == null) throw new ArgumentNullException("query"); return new CompiledQuery(query).Invoke<TDC,TArg1,TResult>; } /// <summary> /// Compiles the query. /// </summary> /// <returns> /// A generic delegate that represents the compiled query. /// </returns> /// <param name="query"> /// The query expression to be compiled. /// </param> /// <typeparam name="TDC "> /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. /// </typeparam> /// <typeparam name="TArg1"> /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. /// </typeparam> /// <typeparam name="TArg2"> /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. /// </typeparam> /// <typeparam name="TResult"> /// Returned type of the delegate returned by the method. /// </typeparam> public static Func<TDC,TArg1,TArg2,TResult> Compile<TDC,TArg1,TArg2,TResult>( [JetBrains.Annotations.NotNull] Expression<Func<TDC,TArg1,TArg2,TResult>> query) where TDC : IDataContext { if (query == null) throw new ArgumentNullException("query"); return new CompiledQuery(query).Invoke<TDC,TArg1,TArg2,TResult>; } /// <summary> /// Compiles the query. /// </summary> /// <returns> /// A generic delegate that represents the compiled query. /// </returns> /// <param name="query"> /// The query expression to be compiled. /// </param> /// <typeparam name="TDC "> /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. /// </typeparam> /// <typeparam name="TArg1"> /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. /// </typeparam> /// <typeparam name="TArg2"> /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. /// </typeparam> /// <typeparam name="TArg3"> /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. /// </typeparam> /// <typeparam name="TResult"> /// Returned type of the delegate returned by the method. /// </typeparam> public static Func<TDC,TArg1,TArg2,TArg3,TResult> Compile<TDC,TArg1,TArg2,TArg3,TResult>( [JetBrains.Annotations.NotNull] Expression<Func<TDC,TArg1,TArg2,TArg3,TResult>> query) where TDC : IDataContext { if (query == null) throw new ArgumentNullException("query"); return new CompiledQuery(query).Invoke<TDC,TArg1,TArg2,TArg3,TResult>; } /// <summary> /// Compiles the query. /// </summary> /// <returns> /// A generic delegate that represents the compiled query. /// </returns> /// <param name="query"> /// The query expression to be compiled. /// </param> /// <typeparam name="TDC "> /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. /// </typeparam> /// <typeparam name="TArg1"> /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. /// </typeparam> /// <typeparam name="TArg2"> /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. /// </typeparam> /// <typeparam name="TArg3"> /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. /// </typeparam> /// <typeparam name="TArg4"> /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. /// </typeparam> /// <typeparam name="TResult"> /// Returned type of the delegate returned by the method. /// </typeparam> public static Func<TDC,TArg1,TArg2,TArg3,TArg4,TResult> Compile<TDC,TArg1,TArg2,TArg3,TArg4,TResult>( [JetBrains.Annotations.NotNull] Expression<Func<TDC,TArg1,TArg2,TArg3,TArg4,TResult>> query) where TDC : IDataContext { if (query == null) throw new ArgumentNullException("query"); return new CompiledQuery(query).Invoke<TDC,TArg1,TArg2,TArg3,TArg4,TResult>; } /// <summary> /// Compiles the query. /// </summary> /// <returns> /// A generic delegate that represents the compiled query. /// </returns> /// <param name="query"> /// The query expression to be compiled. /// </param> /// <typeparam name="TDC "> /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. /// </typeparam> /// <typeparam name="TArg1"> /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. /// </typeparam> /// <typeparam name="TArg2"> /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. /// </typeparam> /// <typeparam name="TArg3"> /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. /// </typeparam> /// <typeparam name="TArg4"> /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. /// </typeparam> /// <typeparam name="TArg5"> /// Represents the type of the parameter that has to be passed in when executing the delegate returned by the method. /// </typeparam> /// <typeparam name="TResult"> /// Returned type of the delegate returned by the method. /// </typeparam> public static Func<TDC,TArg1,TArg2,TArg3,TArg4,TArg5,TResult> Compile<TDC,TArg1,TArg2,TArg3,TArg4,TArg5,TResult>( [JetBrains.Annotations.NotNull] Expression<Func<TDC,TArg1,TArg2,TArg3,TArg4,TArg5,TResult>> query) where TDC : IDataContext { if (query == null) throw new ArgumentNullException("query"); return new CompiledQuery(query).Invoke<TDC,TArg1,TArg2,TArg3,TArg4,TArg5,TResult>; } #endregion } }