EF如何使用LINQ`Where`函数提供的回调从数据库中选择元素?

问题描述 投票:0回答:1

EF如何使用LINQ Where函数提供的回调从数据库中选择元素?

例如,如果我有一个查询context.People.Where(p => isOldEnough(p)),这意味着EF将查询数据库中的所有人员,然后将谓词应用于他们并返回剩余的结果,或者将谓词转换为实际的数据库查询不知何故?

[我知道,一旦以某种方式使用context.People.Where(p => isOldEnough(p))的结果(例如,在迭代或强制转换中),就会对数据库进行实际查询。

我无法在互联网上找到该信息,所以我决定在这里询问。

c# database entity-framework linq predicate
1个回答
0
投票

使用EF6表达式:

var oldEnoughPeople = context.People.Where(p => isOldEnough(p));

其中isOldEnough是代码库中的方法,将引发EF无法将isOldEnough转换为SQL的异常。一个简单的解决方法是将ToList()拍入,以迫使EF评估Linq2Object中的表达式:

var oldEnoughPeople = context.People.ToList().Where(p => isOldEnough(p));

直接的问题是,EF将在应用过滤器之前从数据库中将all个人提取到应用程序服务器的内存中。这可能非常昂贵,特别是在一个Web应用程序中,使用一个用户会话进行测试不会突出问题,但是在生产中,有成百上千个请求进入,事情变得停滞了。

[如果isOldEnough()只是在做类似比较Person.Age> = 18的逻辑,然后将其移到Where子句中:

var oldEnoughPeople = context.People.Where(p => p.Age >= 18);

这允许EF将表达式转换为SQL并将其传递给数据库。返回的唯一数据将是适用的人员记录。

[现在,当涉及到EF Core时,开发人员已经把一个危险的地雷(IMHO)打倒了,因为当EF遇到它无法翻译的原始表达时,它将有效地自动将.ToList()打入引发异常。我相信它确实会发出警告,表明它已经这样做了,但是否则,这可能是一个相当安静的性能陷阱,您应该意识到。但是,至少对于EF Core,最重要的是,它可以转换为SQL的所有查询表达式都将首先应用于SQL。

例如,给出以下表达式:

var oldEnoughPeopleStartingWithS = context.People.Where(p => p.Name.StartsWith("s") && isOldEnough(p));

EF Core将执行查询以选择所有以“ s”开头的人,因为EF可以将string.StartsWith转换为SQL。这些实体将实现,并从中应用isOldEnough检查在内存中。但是,这需要仔细考虑,因为如果这是一个OR操作(p.Name.StartsWith("s") || isOldEnough(p)),EF将像之前的.ToList()示例一样在过滤之前有效地提取all个人记录。

[使用EF开发时,强烈建议对您的数据库使用探查器,以准确检查正在运行的SQL语句,以及这些查询的性能影响和返回的数据量。

© www.soinside.com 2019 - 2024. All rights reserved.