EF Core 3.x - 带Include的简单LINQ无法翻译,客户端评价

EF Core 3.x - simple LINQ with Include can not be translated, client evaluation

我有一个简单的 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();
        }

给我一个运行时异常:

'The LINQ expression 'DbSet .OrderBy(p => p.CompletionDate) .Where(p => __displayCollection_0 .Any(item => item.ProjectID == p.ProjectID))' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.'

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

In such cases, you can explicitly opt into client evaluation by calling methods like AsEnumerable or ToList (AsAsyncEnumerable or ToListAsync for async). By using AsEnumerable you would be streaming the results, but using ToList would cause buffering by creating a list, which also takes additional memory.

在我的例子中,当使用 AsEnumerable() 时出现异常:

IEnumerable does not contain a definition for 'Include' (...)

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

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

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 查询。并且常规的 LINQ 应该能够在列表上执行此操作。

缺点(如果可行)是当您调用“.ToList()”

时,您将遍历整个数据库 table

尝试将 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);