我使用 ((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 给了我以下异常:
LINQ to Entities 查询表达式只能从实现 IQueryable 接口(interface)的实例构造。
最佳答案
这是我在尝试这样做时得出的实际可行答案。异常说“只能从实现 IQueryable 接口(interface)的实例构造”,所以答案似乎很简单:返回一个可查询的东西。返回 .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()
except 让上下文的 QueryProvider 处理查询。生成的 SQL 与您所期望的差不多:
SELECT
[GroupBy1].[A1] AS [C1]
FROM ( SELECT
COUNT(1) AS [A1]
FROM [dbo].[Entity] AS [Extent1]
) AS [GroupBy1]
关于c# - 如何为 IQueryable.Count 获取 ToTraceString,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8302656/