简体   繁体   English

如果我随后在 EF Core 中执行 Select,则对 Include 的过滤将恢复

[英]Filtering on Include reverted if I perform Select afterwards in EF Core

I am trying to use Filtered Includes in EF Core and I have encountered an issue which I can't seem to pinpoint to a specific cause.我正在尝试在 EF Core 中使用过滤的包含,但遇到了一个我似乎无法确定具体原因的问题。

My query looks something like this:我的查询看起来像这样:

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

If I omit the Select part from the query and check the object, it is populated only with the appropriate UserRoles, the ones belonging to the category 3, but upon checking the result of this Select, it contains also the Roles that belong to a different category, concatenated into the ListOfRoles.如果我从查询中省略 Select 部分并检查对象,它只填充了适当的 UserRoles,属于类别 3 的用户角色,但在检查此 Select 的结果时,它还包含属于不同的角色类别,连接到 ListOfRoles。

I would be grateful if anyone had any ideas what could be causing this.如果有人知道可能导致这种情况的原因,我将不胜感激。

Thank you谢谢

Include only applies where you are returning the entity. Include仅适用于您返回实体的情况。 When you use projection with Select you need to filter the data within the Select expression:当您将投影与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();

I believe that String.Join would require client-side evaluation in EF Core.我相信 String.Join 需要在 EF Core 中进行客户端评估。 This can lead to unexpected data being loaded.这可能会导致加载意外数据。 A recommendation to avoid this would be to perform the concatination within the DTO so that the Linq query loads the raw data and can translate that to SQL efficiently:避免这种情况的建议是在 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();

Where in the DTO you would have:在 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); }
    }
}

This ensures the query can run efficiently and translate fully to SQL, then moves the formatting to the DTO.这确保查询可以高效运行并完全转换为 SQL,然后将格式移动到 DTO。

Include will work only if you select entities directly.仅当您直接选择实体时, Include才会起作用。 Once you do the projection ( Select for example) Include is ignored.进行投影(例如Select )后, Include被忽略。 You can try to apply category filtering during the concatenation part:您可以尝试在串联部分应用类别过滤:

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

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

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