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 ,使用int500调用<运算符。 当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);