LINQ 实体框架查询在 EF Core 中不起作用,引发异常

Posted

技术标签:

【中文标题】LINQ 实体框架查询在 EF Core 中不起作用,引发异常【英文标题】:LINQ Entity Framework query not working in EF Core, throwing exception 【发布时间】:2021-12-16 22:45:14 【问题描述】:

我有这个在旧应用程序中工作的实体框架 v4.0 查询,我正在将其转换为 EF Core 版本 5.0。

当我在调试中运行代码时,它会在 .ToList(); 之后抛出以下错误

The LINQ expression 'DbSet<User>()
    .GroupJoin(
        inner: DbSet<Address>(), 
        outerKeySelector: u => u.UserId, 
        innerKeySelector: a => a.UserId, 
        resultSelector: (u, ua) => new  
            u = u, 
            ua = ua
         )' 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 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.

所以,我添加了 .ToList() 并且还尝试了 .ToListAsync() 到查询的末尾,但是这个错误仍然存​​在。

我查看了 docs.microsoft,发现这个示例看起来像我的查询

  var query = from person in people
                join pet in pets on person equals pet.Owner into gj
                from subpet in gj.DefaultIfEmpty()
                select new  person.FirstName, PetName = subpet?.Name ?? String.Empty ; 

更新:我注释掉了加入并删除了错误,但不知道为什么这不起作用。另一篇文章提到如果无法解释 linq 但附加连接看起来很简单,则会生成此错误,对吧?

 var users =
    
                        (from u in this.MyDbContext.User
                         join a in this.MyDbContext.Address
                                     on u.UserId equals a.UserId
                                     into ua
                         //join d in this.MyDbContext.JobTitle
                         //          on e.JobTitleId equals d.JobTitleId
                         from ua_left in ua.DefaultIfEmpty()
                         select new UserViewModel
                         
                             BoardId = u.BoardId,
                             UserId = u.UserId,
                             LastName = u.LastName,
                             FirstName = u.FirstName,
                             JobTitleId = u.JobTitleId,
                             //JobTitle = d.JobTitleDescription,
                             Email = u.Email,
                             Grade = u.Grade,
                             Title = u.Title,
                             //StartDate = ua_left.StartDate,
                         );
  
      var test = users.ToList();

我不确定我错过了什么

var users =

                    (from u in this.MyDbContext.User
                     join a in this.MyDbContext.Address
                                 on u.UserId equals a.UserId
                                 into ua
                     join d in this.MyDbContext.JobTitle
                                 on e.JobTitleId equals d.JobTitleId
                     from ua_left in ua.DefaultIfEmpty()
                     select new UserViewModel
                     
                         BoardId = u.BoardId,
                         UserId = u.UserId,
                         LastName = u.LastName,
                         FirstName = u.FirstName,
                         JobTitleId = u.JobTitleId,
                         JobTitle = d.JobTitleDescription,
                         Email = u.Email,
                         Grade = u.Grade,
                         Title = u.Title,
                         //StartDate = ua_left.StartDate,
                     );



  var test = users.ToList();

在玩完代码后,如果我像这样取出左连接子句,查询将运行并返回数据

var users =

                    (from u in this.MyDbContext.User
                     join a in this.MyDbContext.Address
                                 on u.UserId equals a.UserId
                     join d in this.MyDbContext.JobTitle
                                 on e.JobTitleId equals d.JobTitleId
                     select new UserViewModel
                     
                         BoardId = u.BoardId,
                         UserId = u.UserId,
                         LastName = u.LastName,
                         FirstName = u.FirstName,
                         JobTitleId = u.JobTitleId,
                         JobTitle = d.JobTitleDescription,
                         Email = u.Email,
                         Grade = u.Grade,
                         Title = u.Title,
                         //StartDate = ua_left.StartDate,
                     );



  var test = users.ToList();

我查看了另一个帖子,其他人正在使用相同的左连接。我不确定为什么它不能在 EF Core 上运行。

感谢任何帮助。谢谢。

【问题讨论】:

请同时提及您使用的 EF Core 版本。 您的 UserViewModel 的 StartDate 属性是否可以为空?如果不是,请尝试使其可为空并执行查询。 我想你正在使用 EF Core 3+。虽然没有直接关系,但我相信这是原因***.com/questions/58074844/… - 基本上,查询评估不再在客户端完成。如果方法不能转换为 SQL(或其他)命令,那么它会抛出。如果您想接受这个作为答案,请告诉我,我会添加它(看起来是无法翻译的 DefaultIfEmpty - 您可以将第一部分加载到内存中然后再试一次) 您的查询中的e 是什么? 我注释掉了其中一个连接,错误消失了,但不知道为什么? 【参考方案1】:

虽然没有直接关系,但我相信是原因:EF Linq Error after change from dotnet Core 2.2.6 to 3.0.0


基本上,因为 EF Core 3 查询评估不再在客户端完成。这意味着,如果一个方法不能转换为 SQL 命令,它就会抛出异常。查看代码是无法翻译的DefaultIfEmpty()编辑:into [x] 的多个连接似乎无法翻译。

您“可以”将表加载到内存中然后使用它 - 因为客户端/代码正在处理数据,而不是 EF 试图编译的 SQL 查询。但是,这会加载整个表格,这可能会非常密集 - 取决于大小。

更好的解决方案是使用空值 - 如下所示:(未测试)

var users =
    (
        from u in this.MyDbContext.User
            join a in this.MyDbContext.Address
                on u.UserId equals a.UserId
            join d in this.MyDbContext.JobTitle
                on e.JobTitleId equals d.JobTitleId
        select new UserViewModel
        
            BoardId = u.BoardId,
            UserId = u.UserId,
            LastName = u.LastName,
            FirstName = u.FirstName,
            JobTitleId = u.JobTitleId,
            JobTitle = d.JobTitleDescription,
            Email = u.Email,
            Grade = u.Grade,
            Title = u.Title,
            StartDate = 
                ua == null
                    ? System.Data.SqlTypes.SqlDateTime.MinValue
                    a.StartDate,
        
    );

【讨论】:

嗨,格伦,我对您的解决方案感到困惑。在玩弄了代码之后,当我删除其中一个连接时,错误就消失了。 我想了解 EF Core 的最佳实践如何使多个 JOIN 与 outleft join 一起工作。到目前为止,此查询比旧的 v4 EF 慢。谢谢 删除into ua 修复了我的示例-这很奇怪,因为它在您留下的连接中-但我的错误与您的一致。最佳实践是另一回事——我要说的一件事是关系是要走的路——简化了很多代码。此外,如果连接列可以为空,它将始终为left join

以上是关于LINQ 实体框架查询在 EF Core 中不起作用,引发异常的主要内容,如果未能解决你的问题,请参考以下文章

c# ef框架怎么使用linq语句多表查询?

Entity Framework Core Linq NULL 不起作用的地方

无法从 Linq 查询 EF Core 访问字段值

ASP.NET EF(LINQ/Lambda查询)

EF基于方法的查询语法

LINQ / EF Core 不能在查询中使用 string.Contains