Член IQueryable.Expression
возвращается в IQueryProvider
всеми различными Queryable.*
«операторами» (.Where()
, .Select()
, .Join()
, ...), например:
public static IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate) {
if (source == null)
throw Error.ArgumentNull("source");
if (predicate == null)
throw Error.ArgumentNull("predicate");
return source.Provider.CreateQuery<TSource>(
Expression.Call(
null,
((MethodInfo)MethodBase.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
new Expression[] { source.Expression, Expression.Quote(predicate) }
));
}
(взято из справочного источника)
Обычно это должно быть все выражение.
Ясно, что никто не убьет вас, если вы передадите напрямую всю ссылку на ваш IQueryable
класс через Expression.Constant()
, но я действительно думаю, что это не «кошерно».
Смысл помещения "настоящего" выражения в Expression
(как это делается Enumerable.AsQueryable()
, EF и LINQ-to-SQL, просто чтобы назвать трех IQueryable
поставщиков) заключается в том, что другие внешние классы могут свободно анализировать и манипулировать Expression
и передать его провайдеру так же, как это делает Queryable.Where
, при этом
Expression expression = source.Expression;
// here "expression" is manipulated
return source.Provider.CreateQuery<SomeType>(expression);
Чтобы привести пример ... Существуют некоторые "средства исправления запросов", которые изменяют запрос, например https://github.com/davidfowl/QueryInterceptor (общий модификатор для запросов) или https://github.com/hazzik/DelegateDecompiler, позволяющий:
var employees = (from employee in db.Employees
where employee.FullName == "Test User"
select employee).Decompile().ToList();
где FullName
не отображается в БД и является таким свойством, как:
class Employee
{
[Computed]
public string FullName
{
get { return FirstName + " " + LastName; }
}
(с FirstName
и LastName
, сопоставленными с базой данных). DelegateDecompiler берет Expression
из IQueryable
, ищет свойства с атрибутом Computed
, декомпилирует их и помещает декомпилированный код (преобразованный в дерево выражений) обратно в IQueryable.Expression
(хотя используется IQueryable.Provider.CreateQuery()
)
Если вы хотите сохранить дополнительные данные, вы можете поместить их в Provider
: вы можете создать новый экземпляр класса IQueryProvider
в методе CreateQuery
. Это тоже возвращается операторами Queryable.*
(потому что CreateQuery<>
является методом экземпляра source.Provider
)
person
xanatos
schedule
20.05.2015
Expression
содержит выражение для текущегоIQueryable
, поскольку у нас может быть их цепочка, поэтому каждоеIQueryable
имеет свои собственные и ранее сгруппированные выражения. Но могу ошибаться, так как использую очень давно. - person Sergey Litvinov   schedule 20.05.2015