【问题标题】:EF Core 3.x - simple LINQ with Include can not be translated, client evaluationEF Core 3.x - 带有 Include 的简单 LINQ 无法翻译,客户端评估
【发布时间】:2020-07-05 17:13:27
【问题描述】:

我有一个简单的 LINQ 表达式:

public List<Project> GetCheckedProjects(List<PickedUp> displayCollection)
        {
            IQueryable<Project> query = _context.Projects
                .OrderBy(project => project.CompletionDate)
                .Where(project => displayCollection.Any(item => item.ProjectID == project.ProjectID))
                .Include(project => project.TechnologiesProjects)
                .ThenInclude(techproj => techproj.Technology);
            return query.ToList();
        }

这让我抛出了一个运行时异常:

'LINQ 表达式'DbSet .OrderBy(p => p.CompletionDate) .Where(p => __displayCollection_0 .Any(item => item.ProjectID == p.ProjectID))' 无法翻译。要么以可以翻译的形式重写查询, 或通过插入调用显式切换到客户端评估 AsEnumerable()、AsAsyncEnumerable()、ToList() 或 ToListAsync()。见https://go.microsoft.com/fwlink/?linkid=2101038 更多信息。'

this MSDN article 中提到,在 EF Core 3.x 中发生了重大更改,它们阻止了客户端评估。和

在这种情况下,您可以通过以下方式明确选择加入客户评估 调用 AsEnumerable 或 ToList 等方法(AsAsyncEnumerable 或 ToListAsync 用于异步)。通过使用 AsEnumerable 您将进行流式传输 结果,但使用 ToList 会通过创建一个 列表,这也需要额外的内存。

在我的情况下,当使用 AsEnumerable() 时,我遇到了一个异常:

IEnumerable 不包含“包含”的定义 (...)

在表达式的最后使用ToList() 也很简单,like in this SO answer 不会带来任何积极的结果。

EF Core 2.x 中,我的 LINQ 工作正常。如何绕过这个问题?

【问题讨论】:

    标签: c# entity-framework linq ef-core-3.1


    【解决方案1】:

    尝试将 ID 选择到单独的集合中并使用 Contains

        public List<Project> GetCheckedProjects(List<PickedUp> displayCollection)
        {
            var ids = displayCollection.Select(item => item.ProjectID).ToList();
            IQueryable<Project> query = _context.Projects
                .OrderBy(project => project.CompletionDate)
                .Where(project => ids.Contains(project.ProjectID))
                .Include(project => project.TechnologiesProjects)
                .ThenInclude(techproj => techproj.Technology);
            return query.ToList();
        }
    

    或者,由于此代码将被转换为查询,因此您可以在一行中完成:

    IQueryable<Project> query = _context.Projects
                .OrderBy(project => project.CompletionDate)
                .Where(project => displayCollection.Select(item => item.ProjectID).Contains(project.ProjectID))
                .Include(project => project.TechnologiesProjects)
                .ThenInclude(techproj => techproj.Technology); 
    

    【讨论】:

      【解决方案2】:

      Ef Core 可能有问题:

      displayCollection.Any(item => item.ProjectID == project.ProjectID)
      

      试试这个方法

      public List<Project> GetCheckedProjects(List<PickedUp> displayCollection)
          {
              IQueryable<Project> queryAll = _context.Projects
                  .OrderBy(project => project.CompletionDate)                
                  .Include(project => project.TechnologiesProjects)
                  .ThenInclude(techproj => techproj.Technology);
              
              var query = queryAll
                    .ToList()
                    .Where(project => displayCollection.Any(item => item.ProjectID == project.ProjectID));       
          
              return query;
          }
      

      我认为这应该可行,因为 EF 核心不会将 Where 子句转换为 sql 查询。并且 reqular LINQ 应该能够在 List 上执行此操作。

      缺点(如果可行的话)是当您调用“.ToList()”时,您将遍历整个数据库表

      【讨论】:

      • 实际上它给了我和以前一样的异常。
      猜你喜欢
      • 2020-03-11
      • 2020-06-16
      • 2017-12-27
      • 1970-01-01
      • 2020-03-14
      • 2020-02-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多