【问题标题】:EF Core 5.0 - The linq expression could not be translated. either rewrite the queryEF Core 5.0 - 无法翻译 linq 表达式。要么重写查询
【发布时间】:2021-12-25 04:02:36
【问题描述】:

这个问题已经askedbefore 回答过几次,但不是以一般的方式回答。相反,答案是针对提问者的(这是有道理的)......但我经常使用这种模式,我相信其他人也会这样做,所以我正在寻找一个更普遍的答案。我知道为什么会发生这种情况,但我不确定该怎么做。下面的违规行是

RoleId = ur.First(xu => xu.UserId == x.Id).RoleId,

我的理解是,我必须在投影之前以某种方式对其进行转换,但这就是我遇到的问题。或者使用Contains() 而不是First()(这是一个隐含的Where() 过滤器),但我不确定如何重写它,以便服务器将执行查询,而不是客户端。最好的前进方式是什么?

         var roles = await _roleManager.Roles.ToListAsync();
         var rolesList = roles.Select(x => new {x.Id, x.Name}).ToList();

         var rid = ur.First(xu => xu.UserId == 4).RoleId;
         
         var ur = await _context.UserRoles.ToListAsync();
         var appUsers = await _context.Users
             .Select(x => new AppUserViewModel
             {
                 Id = x.Id,
                 StaffId = x.StaffId,
                 Email = x.Email,
                 UserName = x.UserName,
                 PhoneNumber = x.PhoneNumber,
                 RoleId = ur.First(xu => xu.UserId == x.Id).RoleId,
                 RoleSelectListItems = rolesList.Select(yy => new SelectListItem
                 {
                     Value = yy.Id.ToString(),
                     Text = yy.Name
                 }).ToList()
             })
             .ToListAsync();

【问题讨论】:

  • 你可以试试var rid = _context.UserRoles.Find(4)?.RoleId?
  • 尝试FirstOrDefault 而不是First 。如果它不起作用,我将准备如何避免此类异常的示例。

标签: entity-framework-core


【解决方案1】:

实际上你应该使用IQueryable,而不是列表。

var roles = _roleManager.Roles.AsQueryable();
var ur = _context.UserRoles.AsQueryable();

var appUsers = await _context.Users
    .Select(x => new AppUserViewModel
    {
        Id = x.Id,
        StaffId = x.StaffId,
        Email = x.Email,
        UserName = x.UserName,
        PhoneNumber = x.PhoneNumber,
        RoleId = ur.FirstOrDefault(xu => xu.UserId == x.Id).RoleId,
        RoleSelectListItems = roles.Select(yy => new SelectListItem
        {
            Value = yy.Id.ToString(),
            Text = yy.Name
        }).ToList()
    })
    .ToListAsync();

【讨论】:

  • 您能否详细说明原因?
  • 为什么什么?如何正确编写 LINQ 查询?如何不进行多个数据库往返?对于复杂问题而言,问题过于宽泛。
  • 您说要使用 IQueryable 却没有说明原因。我希望能学到一些东西。那么为什么要使用 IQueryable 呢?我想在这种情况下它可以防止多个数据库往返。谢谢。
  • IQueryable 是查询的构建块。如果加入,请从 IQueryable 中选择,如果可能,LINQ 翻译器将尝试将所有内容组合到一个 SQL 中。由于减少了数据库往返,它应该提高查询的性能。
  • 此外,EF Core 不能在 LINQ 查询中使用本地集合(Contains 除外),因此 IQueryable(由 DbContext 制成)是最佳选择。
【解决方案2】:

我得到了答案。 Linq 将自身发送到数据库,但翻译器无法解释某些表达式,这就是它抛出此错误的原因。因此,例如,如果您的 Linq 表达式引用了一个返回值的方法,那么该方法无法传递给您的数据库,因此您必须先获取该值,然后才能在 Linq 表达式中使用它。

所以在上面的例子中,RoleId = ur.First(xu => xu.UserId == x.Id).RoleId, 实际上是两个表达式,翻译者不知道该怎么处理。第一部分是“将 userRoles 列表中 id 等于用户 id 的第一个对象返回给我”,第二部分是“现在给我 RoleId”。但是你不能把它发送下来——它不能被翻译。所以我必须从 userRoles 列表中获取 RoleId 作为一对单独的事务。

获取角色对象,然后从该对象中分离出 RoleId 值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-24
    • 2020-09-10
    • 2021-10-13
    • 1970-01-01
    • 2020-06-16
    相关资源
    最近更新 更多