【问题标题】:How does the Entity Framework retrieve rows using LINQ with a predicate function?实体框架如何使用带有谓词函数的 LINQ 检索行?
【发布时间】:2018-06-29 19:13:32
【问题描述】:

我是使用实体框架(核心 2.0.1)的新手,据我了解,LINQ 表达式通过实体框架映射到供应商特定的 SQL 查询,例如

from actor in db.Actors
where actor.Name == "Madonna" 
|| actor.Name == "Bruce Lee"
select actor

映射到

SELECT *
FROM Actors
WHERE Name = 'Madonna' 
OR Name = 'Bruce Lee';

我在某处引用了read

EF/Core 将 Where 查询方法调用转换为 SQL 中的 WHERE 子句,并将谓词表达式树(同样,不是谓词函数)转换为 WHERE 子句中的条件。

假设我想在匹配演员姓名时不区分大小写,并在演员姓名前后允许空格。我需要为此使用正则表达式。我尝试执行以下操作

public static bool Contains1(Actor actor)
{
    bool result;
    ISet<string> RegexStrSet = new HashSet<string>(
           new String[]{
                @"Bruce\s+Lee",
                @"Madonna"
           }
           );

    result = false; //assumed
    for (IEnumerator<String> criteria = RegexStrSet.GetEnumerator(); criteria.MoveNext() && !result;)
    {
        if (Regex.Match(actor.Name, @"\s*" + criteria.Current + @"\s*", RegexOptions.IgnoreCase).Success)
        {
            result = true;
        }
    }
    return result;
}

static void Main(string[] args)
        {
            using (var db = new ActorDbContext())
            {
                Predicate<Actor> functPred1 = new Predicate<Actor>(Contains1);


                if ((from actor in db.Actors
                     where functPred1(actor)
                     select actor).Count() == 0
                   )
                {
                ...

这确实有效。我现在假设 where 谓词没有被映射,而是在返回表的行时运行,因此现在是数据库 SQL 查询

SELECT *
FROM Actors

我的问题是,实体框架有三个关于如何检索行的选项。有吗

-如果表太大,则检索整个表并抛出内存不足运行时异常。

- 尽可能多地检索并再次执行,直到评估整个表。

-一次检索和评估一行

如果它尝试一次检索整个表,我应该怎么做才不会崩溃。

编辑: 我复制并连接了Dixin's Application side logging,以查看以下下划线查询发送到服务器的以下内容。注意:仅包含最相关的日志 sn-ps。

foreach (Actor actor in (from actor in db.Actors
                                         where actor.Name == "Madonna"
                                         || actor.Name == "Bruce Lee"
                                         select actor)){ }

日志输出sn-ps:

2018-01-20T21:56:17.0846048+00:00 Information 20101 Microsoft.EntityFrameworkCore.Database.Command
Executed DbCommand (57ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT [actor].[Id], [actor].[AcademyWinner], [actor].[Age], [actor].[Name]
FROM [Actors] AS [actor]
WHERE [actor].[Name] IN (N'Madonna', N'Bruce Lee')

foreach (Actor actor in (from actor in db.Actors
                      where functPred1(actor)
                      select actor)){ }

日志输出sn-ps:

2018-01-20T21:56:17.1878434+00:00 Warning 20500 Microsoft.EntityFrameworkCore.Query
The LINQ expression 'where Invoke(__functPred1_0, [actor])' could not be translated and will be evaluated locally.

2018-01-20T21:56:17.2269410+00:00 Information 20101 Microsoft.EntityFrameworkCore.Database.Command
Executed DbCommand (8ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT [actor].[Id], [actor].[AcademyWinner], [actor].[Age], [actor].[Name]
FROM [Actors] AS [actor]

所以看起来整个表都是从数据库服务器中检索的。实体框架一次只检索表的一个子集,评估行上的谓词函数并继续直到查询测试了表中的每一行以防止内存不足运行时异常,这不是更聪明吗并且不会为其他应用程序占用 RAM。

【问题讨论】:

  • 实体框架在正常情况下使用 IQueryable,它不会将整个表加载到内存中 developerhandbook.com/entity-framework/…。但是,在您的特殊情况下,您可以使用 sql profiler 来查看访问服务器的实际查询是什么
  • EF 将一次性检索所有符合条件的行。它没有内部查询结果队列,每个 IQueryable 枚举只会执行一个查询(延迟加载除外)

标签: c# sql entity-framework linq entity-framework-core


【解决方案1】:

我的问题是这样的,实体框架有三种选择 将检索行。有吗

-如果表太大,则检索整个表并抛出内存不足运行时异常。

- 尽可能多地检索并再次执行,直到评估整个表。

-一次检索和评估一行

  1. 根据您在 Main() 下的代码,您不会检索整个表。就像您将 LINQ 表达式转换为 SQL 一样,这就是 EF 上下文正在做的事情(通过正则表达式进行过滤)。
  2. 嗯,它会一次性检索您尝试查询的所有行。
  3. 它不会一次检索和评估一行。它将抓取与您的 where 子句匹配的所有记录。

我认为您永远不会在没有某种过滤器/限制的情况下调用 EF 上下文,当然,如果您的机器没有运行它的规范,程序将会崩溃。但是,如果您练习良好的实体关系模型,我认为您不会在一张表中达到超过 4GB 的数据。

不要太担心获取一个表中的所有行(因为您一开始不会发现自己这样做)。

这里有一些链接来补充关于 EF 性能的想法:

【讨论】:

  • 抱歉,我认为问题与您的答案之间没有太大关系。这里唯一重要的是 ef-core 自动切换到客户端评估,因为谓词不是可以转换为 SQL 的 Expression。即:将从数据库中提取所有实体,然后(当它们都存在时)过滤它们。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多