我使用((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 query expressions can only be constructed from instances that implement the IQueryable interface.
答案 0 :(得分:5)
当我尝试这样的时候,我想出了一个实际的工作答案。例外情况说“只能从实现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]
答案 1 :(得分:2)
您无法为&#39; Count&#39;创建查询对象。因为它不会返回IQueryable(这是有意义的 - 它返回一个值)。
您有两种选择:
(推荐)使用eSQL:
context.CreateQuery<YourEntity>("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
});
}