首页 > 解决方案 > 如果我之后在 EF Core 中执行 Select,则过滤包括恢复

问题描述

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

我的查询看起来像这样:

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。

如果有人有任何想法可能导致这种情况,我将不胜感激。

谢谢

标签: c#.netentity-frameworklinqentity-framework-core

解决方案


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。


推荐阅读