简体   繁体   English

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

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

I have a simple LINQ expression:我有一个简单的 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();
        }

that drops me an runtime exception:这让我遇到了一个运行时异常:

'The LINQ expression 'DbSet.OrderBy(p => p.CompletionDate).Where(p => __displayCollection_0.Any(item => item.ProjectID == p.ProjectID))' could not be translated. 'LINQ 表达式'DbSet.OrderBy(p => p.CompletionDate).Where(p => __displayCollection_0.Any(item => item.ProjectID == p.ProjectID))' 无法翻译。 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().以可翻译的形式重写查询,或通过插入对 AsEnumerable()、AsAsyncEnumerable()、ToList() 或 ToListAsync() 的调用显式切换到客户端评估。 See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.'有关详细信息,请参阅https://go.microsoft.com/fwlink/?linkid=2101038

In this MSDN article it is mentioned, that in EF Core 3.x were breaking changes, and they prevent client evaluation.这篇 MSDN 文章中提到,在EF Core 3.x中发生了重大更改,它们阻止了客户端评估。 And

In such cases, you can explicitly opt into client evaluation by calling methods like AsEnumerable or ToList (AsAsyncEnumerable or ToListAsync for async).在这种情况下,您可以通过调用 AsEnumerable 或 ToList(AsAsyncEnumerable 或 ToListAsync 用于异步)等方法来显式选择客户端评估。 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 您将流式传输结果,但使用 ToList 会通过创建一个列表来导致缓冲,这也需要额外的 memory。

In my case, when using AsEnumerable() I am geting an exception:就我而言,使用AsEnumerable()时出现异常:

IEnumerable does not contain a definition for 'Include' (...) IEnumerable 不包含“包含”的定义 (...)

Also simple using ToList() at very end of expression, like in this SO answe r, does not bring any positive result.在表达式的最后使用ToList()也很简单,就像在这个 SO answe r 中一样,不会带来任何积极的结果。

In EF Core 2.x my LINQ works fine.EF Core 2.x中,我的 LINQ 工作正常。 How to walk around this problem?如何绕过这个问题?

Try selecting the ids into separate collection and using Contains :尝试将 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();
    }

Or, since this code will be translated to query you can do it in one line:或者,由于此代码将被转换为查询,因此您可以在一行中完成:

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); 

Ef Core might be having trouble with the line: Ef Core 可能会遇到以下问题:

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

Try doing it this way尝试这样做

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;
    }

I think this should work because the EF core will not be translating the Where clause into a sql query.我认为这应该可行,因为 EF 核心不会将 Where 子句转换为 sql 查询。 And reqular LINQ should be able to do it on a List.并且要求 LINQ 应该能够在列表上做到这一点。

The downside (if it works) is that you are going to loop through the entire database table when you call ".ToList()"缺点(如果有效)是当您调用“.ToList()”时,您将遍历整个数据库表

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM