如何获取IQueryable.Count的ToTraceString

我使用((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), "Count", new Type[] { source.ElementType }, source.Expression)); } 

但是然后CreateQuery给了我以下exception:

LINQ to Entities query expressions can only be constructed from instances that implement the IQueryable interface.

这是我在尝试这样的时候想出的实际工作答案。 例外情况说“只能从实现IQueryable接口的实例构建”,所以答案看似简单:返回一个可查询的东西。 返回.Count()时有可能吗? 是!

 public partial class YourObjectContext { private static MethodInfo GetMethodInfo(Expression expression) { return ((MethodCallExpression)expression.Body).Method; } public IQueryable CreateScalarQuery(Expression> expression) { return QueryProvider.CreateQuery( Expression.Call( method: GetMethodInfo(() => Queryable.Select(null, (Expression>)null)), arg0: Expression.Call( method: GetMethodInfo(() => Queryable.AsQueryable(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] 

您不能为’Count’创建查询对象,因为它不返回IQueryable(这是有意义的 – 它返回单个值)。

你有两个选择:

  • (推荐)使用eSQL:

     context.CreateQuery("select count(1) from YourEntitySet").ToTraceString() 
  • 使用Reflection来调用不执行IQueryable检查的私有方法(由于显而易见的原因,这是错误的,但如果你只是需要它进行调试,它可能很方便):

     public static IQueryable CountCompile(this IQueryable source) { // you should cache this MethodInfo return (IQueryable)source.Provider.GetType().GetMethod("CreateQuery", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] {typeof (Expression), typeof (Type)}, null) .Invoke(source.Provider, new object[] { Expression.Call( typeof (Queryable), "Count", new[] {source.ElementType}, source.Expression), source.ElementType }); }