【问题标题】:Filtering on Include reverted if I perform Select afterwards in EF Core如果我之后在 EF Core 中执行 Select,则过滤包括恢复
【发布时间】:2021-12-13 14:01:05
【问题描述】:

我正在尝试在 EF Core 中使用过滤包含,但遇到了一个我似乎无法确定具体原因的问题。

我的查询如下所示:

context.Users.Include(u=>u.UserRoles.Where(r => r.Role.Category == 3))
             .ThenInclude(r=>r.Role).Where(u => u.userId == currentUserId)
             .Select(u=> new UserDTO()
{
    UserDisplayName= u.Name,
    ListOfRoles = String.Join(",", u.UserRoles.Select(u => u.Role.DisplayName))
}).FirstOrDefaultAsync();

如果我从查询中省略 Select 部分并检查对象,则它仅填充适当的 UserRoles,属于类别 3 的那些,但在检查此 Select 的结果时,它还包含属于的角色到不同的类别,连接到 ListOfRoles。

如果有人知道可能是什么原因,我将不胜感激。

谢谢

【问题讨论】:

  • 投影(选择新...)禁用Includes。
  • 谢谢你的提示,它回答了我的问题

标签: c# .net entity-framework linq entity-framework-core


【解决方案1】:

Include 仅适用于您返回实体的情况。当您使用带有Select 的投影时,您需要过滤Select 表达式中的数据:

context.Users
    .Where(u => u.userId == currentUserId)
    .Select(u=> new UserDTO()
    {
        UserDisplayName= u.Name,
        ListOfRoles = String.Join(",", u.UserRoles
            .Where(ur => ur.Role.Catecory == 3)
            .Select(ur => ur.Role.DisplayName))
    }).SingleOrDefaultAsync();

我相信 String.Join 需要在 EF Core 中进行客户端评估。这可能会导致加载意外数据。避免这种情况的建议是在 DTO 中执行连接,以便 Linq 查询加载原始数据并可以有效地将其转换为 SQL:

context.Users
    .Where(u => u.userId == currentUserId)
    .Select(u=> new UserDTO()
    {
        UserDisplayName= u.Name,
        Roles = u.UserRoles
            .Where(ur => ur.Role.Catecory == 3)
            .Select(ur => ur.Role.DisplayName))
            .ToList();
    }).SingleOrDefaultAsync();

您将在 DTO 中的哪个位置:

[Serializable]
public class UserDTO
{
    public string UserDisplayName { get; set; }
    public IList<string> Roles { get; set; } = new List<string>();
    public string ListOfRoles
    {
        get { return string.Join(",", Roles); }
    }
}

这确保查询可以高效运行并完全转换为 SQL,然后将格式移至 DTO。

【讨论】:

  • 非常感谢您的回答
【解决方案2】:

Include 仅在您直接选择实体时才有效。一旦你进行投影(例如SelectInclude 将被忽略。您可以尝试在连接部分应用类别过滤:

context.Users
    .Where(u => u.userId == currentUserId)
    .Select(u=> new UserDTO()
    {
        UserDisplayName= u.Name,
        ListOfRoles = String.Join(",", u.UserRoles.Where(r => r.Role.Category == 3).Select(u => u.Role.DisplayName))
    })
    .FirstOrDefaultAsync();

【讨论】:

  • 这就是我最终为了使其工作而做的事情,但根据您的评论“如果在调用之后使用 Select,则忽略包含调用。”我现在也能理解为什么它不起作用了,非常感谢。
  • @ConstantinDinuVasiliu 很乐意提供帮助!如果答案对您有用,请将其标记为accepted one(答案旁边的复选标记)。
猜你喜欢
  • 2017-09-22
  • 2019-07-22
  • 2020-08-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-01
  • 2018-05-06
相关资源
最近更新 更多