entity frameworkfilter“Expression <Func >”
我正在尝试为Entity framework List创建一个filter方法,并更好地理解Expression<Func<...
我有这样的测试function。
public IQueryable Filter(IEnumerable src, Expression<Func> pred) { return src.AsQueryable().Where(pred); }
如果我这样做:
context.Table.Filter(e => e.ID < 500);
或这个:
context.Table.Filter(e => e.SubTable.Where(et => et.ID 0 && e.ID < 500);
这一切都运作良好。
但如果我这样做:
context.Table.Filter(e => e.SubTable.Filter(et => et.ID 0 && e.ID < 500);
或这个:
context.Table.Where(e => e.SubTable.Filter(et => et.ID 0 && e.ID < 500);
我收到一个错误。 LINQ to Entities does not recognize the method ...Filter...
为什么它适用于一个案例而不是加法器? 我应该在Filter中更改它以使用相关表。 我更喜欢远离其他外部库,因为我想要的是学习它是如何工作的,并且能够在将来的任何场景中使用它。
在前两种情况下,filter正确地在数据库中运行。
乔恩和蒂姆已经解释了为什么它不起作用。
假设Filter
中的filter代码不是很简单,您可以更改Filter
以便它返回EF可以翻译的表达式。
我们假设你有这个代码:
context.Table.Where(x => x.Name.Length > 500);
您现在可以创建一个返回此表达式的方法:
Expression> FilterByNameLength(int length) { return x => x.Name.Length > length; }
用法如下:
context.Table.Where(FilterByNameLength(500));
您在FilterByNameLength
构建的表达式可以是任意复杂的,只要您可以将其直接传递给Where
。
理解Expression
和Func<>
之间的区别很有用。
Expression
e => e.ID < 500
存储有关该表达式的信息:有一个T
e
,您正在访问属性ID
,使用int
值500
调用<
运算符。 当EF看到它时,它可能会变成类似[SomeTable].[ID] < 500
东西[SomeTable].[ID] < 500
。
A Func
e => e.ID < 500
是一种等效于以下的方法:
static bool MyMethod(T e) { return e.ID < 500; }
它被编译为执行此操作的IL代码; 它不是设计为“重构”成SQL查询或其他任何东西,只运行。
当EF获取你的Expression
,它必须理解它的每一部分,因为它使用它来构建SQL查询。 它被编程为知道现有Where
方法的含义。 它不知道你的Filter
方法意味着什么,即使它是一个简单的方法,所以它只是放弃了。
为什么它适用于一个案例而不是加法器?
因为EF并不真正“了解”您的Filter
方法。 它不了解它的意图,因此它不知道如何将其转换为SQL。 将它与Where
等相比较,它确实理解。
你在初始表上直接调用它的版本是可行的 ,因为这样你就不会得到一个包含对Filter
的调用的表达式树 – 它只是直接调用Filter
,这反过来会构建一个查询…但是一个EF了解哪个。
如果你能找到一种方法让你的Filter
方法在EF查询中工作,我会感到非常惊讶……但是你已经说过使用Where
无论如何都在使用,那么为什么要使用Filter
呢? 我使用Where
版本 – 或者更好的是,使用带有谓词的Any
重载:
context.Table.Filter(e => e.SubTable.Any(et => et.ID < 500) && e.ID < 500);