Ответ 1
Вот реальный рабочий ответ, который я придумал, когда я попытался сделать то же самое. Исключение говорит, что "может быть создано только из экземпляров, реализующих интерфейс 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]