我使用((ObjectQuery)IQueryable).ToTraceString()来获取和调整将要由LINQ执行的sql代码.
我的问题是,不像大多数IQueryable方法IQueryable.Count定义如下:
public static int Count(this IQueryable source) { return (int)source.Provider.Execute( Expression.Call( typeof(Queryable),"Count",new Type[] { source.ElementType },source.Expression)); }
执行查询而不编译并返回IQueryable.
我想这样做的伎俩:
public static IQueryable CountCompile(this IQueryable source) { return source.Provider.CreateQuery( Expression.Call( typeof(Queryable),source.Expression)); }
但是,然后CreateQuery给我以下异常:
LINQ to Entities查询表达式只能从实现IQueryable接口的实例中构建.
解决方法
当我尝试这样做时,我想出了一个实际的工作答案.异常说“只能从实现IQueryable接口的实例构造”,所以答案看起来很简单:返回一个可查询的东西.返回.Count()可以这样吗?是!
public partial class YourObjectContext { private static MethodInfo GetMethodInfo(Expression<Action> expression) { return ((MethodCallExpression)expression.Body).Method; } public IQueryable<TResult> CreateScalarQuery<TResult>(Expression<Func<TResult>> expression) { return QueryProvider.CreateQuery<TResult>( Expression.Call( method: GetMethodInfo(() => Queryable.Select<int,TResult>(null,(Expression<Func<int,TResult>>)null)),arg0: Expression.Call( method: GetMethodInfo(() => Queryable.AsQueryable<int>(null)),arg0: Expression.NewArrayInit(typeof(int),Expression.Constant(1))),arg1: Expression.Lambda(body: expression.Body,parameters: new[] { Expression.Parameter(typeof(int)) }))); } }
使用它:
var query = context.CreateScalarQuery(() => context.Entity.Count()); MessageBox.Show(((ObjectQuery)query).ToTraceString());
基本上,这样做是在一个子选择中包装一个非IQueryable查询.它将查询转换为
from dummy in new int[] { 1 }.AsQueryable() select context.Entity.Count()
除了让上下文的QueryProvider处理查询.生成的sql几乎是你应该期望的:
SELECT [GroupBy1].[A1] AS [C1] FROM ( SELECT COUNT(1) AS [A1] FROM [dbo].[Entity] AS [Extent1] ) AS [GroupBy1]