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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 11:58:26  来源:igfitidea点击:

Entity Framework Filter "Expression<Func<T, bool>>"

c#entity-frameworklambda

提问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 Filteris not trivial, you could change Filterso 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 FilterByNameLengthcan 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 Filtermethod. 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 Whereetc, 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 Filterdirectly, 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 Filtermethod to work within an EF query... but you've already said that using Whereworks anyway, so why use Filterat all? I'd use the Whereversion - or better yet, use the Anyoverload 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 Expressione => e.ID < 500stores the info about that expression: that there's a Te, that you're accessing the property ID, calling the <operator with the intvalue 500. When EF looks at that, it might turn it into something like [SomeTable].[ID] < 500.

AnExpressione => e.ID < 500存储有关该表达式的信息:有一个Te,您正在访问该属性ID,并<使用intvalue调用运算符500。当 EF 看到它时,它可能会将它变成类似[SomeTable].[ID] < 500.

A Funce => e.ID < 500is a method equivalent to:

AFunce => 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 Wheremethod means. It does not know what your Filtermethod means, even though it's a trivial method, so it just gives up.

当 EF 接受你的 . 时Expression,它必须理解它的每一部分,因为它使用它来构建 SQL 查询。它被编程为了解现有Where方法的含义。它不知道你的Filter方法是什么意思,即使它是一个微不足道的方法,所以它就放弃了。