c# - Entity Framework 如何使用带有谓词函数的 LINQ 检索行?

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

我是使用 Entity Framework (核心 2.0.1)的新手,据我所知,LINQ 表达式通过 Entity Framework 映射到供应商特定的 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 translates Where query method call to WHERE clause in SQL, and translates the predicate expression tree (again, not predicate function) to the condition in WHERE clause.

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

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

我的问题是, Entity Framework 在如何检索行方面有三个选项。是吗

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

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

-一次检索和评估一行

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

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

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

日志输出片段:

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)){ }

日志输出片段:

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]

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

最佳答案

My question is this, the entity framework has three options on how it will retrieve the rows. Does it

-Retrieve the entire table and throw a run out of memory runtime exception if the table is too big.

-Retrieve as much as it can handle and do it again until the entire table has been evaluated.

-Retrieve and evaluate one row at a time

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

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

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

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

关于c# - Entity Framework 如何使用带有谓词函数的 LINQ 检索行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48359844/

相关文章:

c# - 操作超时和 (504) 网关超时之间的区别

c# - sleep /等待很长时间

c# - 转换从 Linq.Dynamic 返回的对象

c# - Entity Framework 上的多态交叉关联

performance - Entity Framework 生成的 SQL 缺少联接

c# - 在 IEnumerable.Select 中调用异步方法

c# - F# 列表到 C# IEnumerable : most efficient method?

java - 为什么 hibernate 只创建第一个表?

mysql - 无法从 Left JoinWhere 和 group by 中找到预期结果

sql - 如何设计两个相互依赖的表?也就是说,TableA 的行不能在 TableB 中没有行存在,反之亦然