IQueryable.Expression
成员由所有不同的Queryable.*
“操作符”(.Where()
, .Select()
, .Join()
, ...)反馈给IQueryProvider
。
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) }
));
}
(摘自参考来源)
通常应该是整个表达式。
显然,如果您直接通过Expression.Constant()
将整个引用传递给您的IQueryable
类,没有人会杀了你,但我认为这不是“正当的”。
在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从
IQueryable
中获取
Expression
,搜索具有
Computed
属性的属性,对其进行反编译,并将反编译的代码(转换为表达式树)放回
IQueryable.Expression
(通过使用
IQueryable.Provider.CreateQuery()
)。
如果您想保存其他数据,可以将其放入
Provider
中:您可以在
CreateQuery
方法中生成
IQueryProvider
类的新实例。这也由
Queryable.*
运算符反馈(因为
CreateQuery<>
是
source.Provider
的实例方法)。
Expression
属性保存当前IQueryable
的表达式,因为我们可以有一系列的IQueryable
,所以每个IQueryable
都有它自己和之前分组的表达式。但是我可能错了,因为我很久以前使用过它。 - Sergey Litvinov