Ped*_*Kid 16 c# lambda entity-framework
我正在尝试为Entity框架列表创建一个过滤器方法并更好地理解 Expression<Func<...
我有这样的测试功能.
public IQueryable<T> Filter<T>(IEnumerable<T> src, Expression<Func<T, bool>> pred)
{
return src.AsQueryable().Where(pred);
}
Run Code Online (Sandbox Code Playgroud)
如果我这样做:
context.Table.Filter(e => e.ID < 500);
Run Code Online (Sandbox Code Playgroud)
或这个:
context.Table.Filter(e => e.SubTable.Where(et => et.ID < 500).Count() > 0 && e.ID < 500);
Run Code Online (Sandbox Code Playgroud)
一切都运作良好.
但如果我这样做:
context.Table.Filter(e => e.SubTable.Filter(et => et.ID < 500).Count() > 0 && e.ID < 500);
Run Code Online (Sandbox Code Playgroud)
或这个:
context.Table.Where(e => e.SubTable.Filter(et => et.ID < 500).Count() > 0 && e.ID < 500);
Run Code Online (Sandbox Code Playgroud)
我收到一个错误. LINQ to Entities does not recognize the method ...Filter...
为什么它适用于一个案例而不是加法器?我应该在Filter中更改它以使用相关表.我更喜欢远离其他外部库,因为我想要的是学习它是如何工作的,并且能够在将来的任何场景中使用它.
在前两种情况下,过滤器在数据库中正确运行.
Dan*_*rth 26
乔恩和蒂姆已经解释了为什么它不起作用.
假设里面的过滤器代码Filter不是微不足道的,你可以改变Filter它以便它返回一个EF可以翻译的表达式.
我们假设你有这个代码:
context.Table.Where(x => x.Name.Length > 500);
Run Code Online (Sandbox Code Playgroud)
您现在可以创建一个返回此表达式的方法:
Expression<Func<YourEntity, bool>> FilterByNameLength(int length)
{
return x => x.Name.Length > length;
}
Run Code Online (Sandbox Code Playgroud)
用法如下:
context.Table.Where(FilterByNameLength(500));
Run Code Online (Sandbox Code Playgroud)
你在里面建立的表达式FilterByNameLength可以是任意复杂的,只要你可以直接传递给它Where.
Tim*_* S. 10
这是非常有用的理解之间的差异Expression<Func<>>和Func<>.
一个Expression e => e.ID < 500存储有关表达的信息:这有一个T e,你所访问的属性ID,调用<与运营商int价值500.当EF看到它时,它可能会变成类似的东西[SomeTable].[ID] < 500.
A Func e => e.ID < 500是一种等效于的方法:
static bool MyMethod(T e) { return e.ID < 500; }
Run Code Online (Sandbox Code Playgroud)
它被编译为执行此操作的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);
Run Code Online (Sandbox Code Playgroud)