实体框架如何使用具有谓词函数的LINQ检索行?

时间:2018-01-20 18:46:21

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

我是使用实体框架(核心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转换查询方法在SQL中调用WHERE子句,并将谓词表达式树(同样,不是谓词函数)转换为WHERE子句中的条件。

假设我想在匹配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
                   )
                {
                ...

这确实有效。我现在假设谓词没有映射到哪里但是在返回表的行时运行,所以现在数据库SQL查询

SELECT *
FROM Actors

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

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

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

- 一次检索并评估一行

如果它试图一次性检索整个表格,我该怎么办才不会崩溃。

编辑: 我复制并连接了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]

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

1 个答案:

答案 0 :(得分:0)

  

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

     

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

     

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

     

- 一次检索并评估一行

  1. 根据您在Main()下的代码,您不会检索整个表。就像你将LINQ表达式翻译成SQL一样,这就是EF上下文正在做的事情(通过正则表达式进行过滤)。
  2. 好吧,它将一次性检索您尝试查询的所有行。
  3. 它不会一次检索和评估一行。它将获取与where子句匹配的所有记录。
  4. 我不认为你会在没有某种过滤器/限制的情况下调用EF上下文,当然如果你的机器没有运行它的规格,程序也会崩溃。但是,如果您练习良好的实体关系模型,我认为您不会在一个表中获得超过4GB的数据。

    不要担心在一个表中获取所有行(因为你不会发现自己首先这样做了。)

    以下是一些补充有关EF表现的想法的链接: