C# 实体框架过滤器“Expression<Func<T, bool>>”
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18337692/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Entity Framework Filter "Expression<Func<T, bool>>"
提问by Pedro.The.Kid
I'm trying to create a filter method for Entity framework List and understand better the Expression<Func<...
我正在尝试为实体框架列表创建过滤器方法并更好地理解 Expression<Func<...
I have a Test Function like this.
我有一个这样的测试功能。
public IQueryable<T> Filter<T>(IEnumerable<T> src, Expression<Func<T, bool>> pred)
{
return src.AsQueryable().Where(pred);
}
and if I do this:
如果我这样做:
context.Table.Filter(e => e.ID < 500);
or this:
或这个:
context.Table.Filter(e => e.SubTable.Where(et => et.ID < 500).Count() > 0 && e.ID < 500);
it all works well.
这一切都很好。
But if I do this:
但如果我这样做:
context.Table.Filter(e => e.SubTable.Filter(et => et.ID < 500).Count() > 0 && e.ID < 500);
or this:
或这个:
context.Table.Where(e => e.SubTable.Filter(et => et.ID < 500).Count() > 0 && e.ID < 500);
I receive one error. LINQ to Entities does not recognize the method ...Filter...
我收到一个错误。 LINQ to Entities does not recognize the method ...Filter...
Why it works in one case and not in the adder? What should I change in the Filter for it to work with related tables. I prefer to stay away from other external library's as what I want is to learn how it works and be able to use it in any scenario in future.
为什么它适用于一种情况而不适用于加法器?我应该在过滤器中更改什么才能使用相关表。我更喜欢远离其他外部库,因为我想要的是了解它是如何工作的,并能够在未来的任何场景中使用它。
In the first two cases the filter runs in the database correctly.
在前两种情况下,过滤器在数据库中正确运行。
采纳答案by Daniel Hilgarth
Jon and Tim already explained why it doesn't work.
乔恩和蒂姆已经解释了为什么它不起作用。
Assuming that the filter code inside Filter
is not trivial, you could change Filter
so that it returns an expression EF can translate.
假设里面的过滤器代码Filter
不是微不足道的,您可以进行更改Filter
,使其返回一个 EF 可以翻译的表达式。
Let's assume you have this code:
假设您有以下代码:
context.Table.Where(x => x.Name.Length > 500);
You can now create a method the returns this expression:
您现在可以创建一个返回此表达式的方法:
Expression<Func<YourEntity, bool>> FilterByNameLength(int length)
{
return x => x.Name.Length > length;
}
Usage would be like this:
用法如下:
context.Table.Where(FilterByNameLength(500));
The expression you build inside FilterByNameLength
can be arbitrarily complex as long as you could pass it directly to Where
.
您在内部构建的表达式FilterByNameLength
可以是任意复杂的,只要您可以将其直接传递给Where
.
回答by Jon Skeet
Why it works in one case and not in the adder?
为什么它适用于一种情况而不适用于加法器?
Because EF doesn't really "know" about your Filter
method. It has no understanding of what it's meant to do, so it doesn't know how to translate it into SQL. Compare that with Where
etc, which it doesunderstand.
因为 EF 并不真正“了解”您的Filter
方法。它不了解它的意图,因此它不知道如何将其转换为 SQL。相比之下,与Where
等,它不明白。
The version where you call it directlyon the initial table works because that way you don't end up with an expression tree containing a call to Filter
- it just calls Filter
directly, which in turn doesbuild up a query... but one which EF understands.
在那里你把它的版本直接在初始表的作品,因为这样你不包含调用的表达式目录树结束了Filter
-它只是调用Filter
直接,这又确实建立一个查询......但其中一个EF明白。
I'd be very surprised if you could work out a way of getting your Filter
method to work within an EF query... but you've already said that using Where
works anyway, so why use Filter
at all? I'd use the Where
version - or better yet, use the Any
overload which takes a predicate:
如果您能找到一种让您的Filter
方法在 EF 查询中工作的方法,我会感到非常惊讶……但您已经说过Where
无论如何使用都有效,那么为什么要使用Filter
呢?我会使用Where
版本 - 或者更好的是,使用Any
带有谓词的重载:
context.Table.Filter(e => e.SubTable.Any(et => et.ID < 500) && e.ID < 500);
回答by Tim S.
It's useful to understand the difference between Expression<Func<>>
and Func<>
.
这是非常有用的理解之间的差异Expression<Func<>>
和Func<>
。
An Expression
e => e.ID < 500
stores the info about that expression: that there's a T
e
, that you're accessing the property ID
, calling the <
operator with the int
value 500
. When EF looks at that, it might turn it into something like [SomeTable].[ID] < 500
.
AnExpression
e => e.ID < 500
存储有关该表达式的信息:有一个T
e
,您正在访问该属性ID
,并<
使用int
value调用运算符500
。当 EF 看到它时,它可能会将它变成类似[SomeTable].[ID] < 500
.
A Func
e => e.ID < 500
is a method equivalent to:
AFunc
e => e.ID < 500
是一个等价于的方法:
static bool MyMethod(T e) { return e.ID < 500; }
It is compiled as IL code that does this; it's not designed to be 'reconstituted' into a SQL query or anything else, only run.
它被编译为执行此操作的 IL 代码;它不是设计为“重组”为 SQL 查询或其他任何东西,只能运行。
When EF takes your Expression
, it must understand every piece of it, because it uses that to build a SQL query. It is programmed to know what the existing Where
method means. It does not know what your Filter
method means, even though it's a trivial method, so it just gives up.
当 EF 接受你的 . 时Expression
,它必须理解它的每一部分,因为它使用它来构建 SQL 查询。它被编程为了解现有Where
方法的含义。它不知道你的Filter
方法是什么意思,即使它是一个微不足道的方法,所以它就放弃了。