【问题标题】:Linq to entities group join on multiple tablesLinq to entity group join 多个表
【发布时间】:2023-03-31 18:29:01
【问题描述】:

我正在尝试使用into 而不是group by 对具有一对多关系的多个表执行组连接。但有些不对劲。我得到用户拥有的每个角色的重复记录。

from compUsr in Repository.All<CompanyUser>()
join usr in Repository.All<User>() on compUsr.UserId equals usr.Id
join usrRole in Repository.All<UserRole>() on usr.Id equals usrRole.UserId
join role in Repository.All<Role>() on usrRoles.RoleId equals role.Id into roles
    select new UserDTO()
    {
        Id = usr.Id,
        Email = usr.Email
        Roles = roles.Select(r => new RoleDTO()
        {
            Id = r.Id
        })
    }

如果我删除 Role 表上的联接,并将 into 语句放在 UserRole 上,分组就像一个魅力,但 UserRole 只是一个链接表,所以 Role 表是我感兴趣的表。任何想法如何尽可能简单地分组?谢谢!

【问题讨论】:

    标签: c# entity-framework linq-to-entities


    【解决方案1】:
    from compUsr in Repository.All<CompanyUser>()
    join usr in Repository.All<User>() on compUsr.UserId equals usr.Id
    join usrRole in Repository.All<UserRole>() on usr.Id equals usrRole.UserId
    join role in Repository.All<Role>() on usrRoles.RoleId equals role.Id
    group new { usr, role } by usr into grp
                        select new
                        {
                            Id = grp.Key.Id,
                            Email = grp.Key.Email,
                            Roles = grp.Select(r => new RoleDTO()
                            {
                                Id = r.role.Id
                            })
                        };
    

    【讨论】:

      【解决方案2】:

      导航属性的存在是有原因的。它们使代码更加简洁和声明性。

      有了导航属性,这很容易:

      from usr in context.Users // or Repository.All<User>()
      select new UserDto
      {
          Id = usr.Id,
          Email = usr.Email,
          Roles = usr.UserRoles.Select(ur => ur.Roles)
                     .Select(r => new RoleDTO()
                                  {
                                      Id = r.Id
                                  }
      }
      

      我不知道您为什么还要加入CompanyUser(您似乎没有使用它),但是如果您需要它,您应该从那里开始查询并使用导航属性来访问其他实体。

      另外,我假设您在 RoleDto 中有更多 Role 属性。如果没有,则不需要选择Role 实体,因为UserRoles 已经包含RoleId

      所以这取决于你。您可以坚持这样的信条,即存储库调用应仅限于一个实体(“单一责任”的非常狭窄的定义),或者将导航属性用于它们的发明目的,并考虑对子节点负责的聚合根它封装了。

      【讨论】:

        【解决方案3】:
        from compUsr in Repository.All<CompanyUser>()
        join usr in Repository.All<User>() on compUsr.UserId equals usr.Id into eGroup
        from u in eGroup.DefaultIfEmpty()
        join usrRole in Repository.All<UserRole>() on u.Id equals usrRole.UserId into eGroup1
        from ur in eGroup1.DefaultIfEmpty()
        join role in Repository.All<Role>() on ur.RoleId equals role.Id into eGroup2
        from r in eGroup2.DefaultIfEmpty()
        group new { u, r } by u into grp
        select new
        {
              Id = grp.Key.Id,
              Email = grp.Key.Email,
              Roles = grp.FirstOrDefault().r.Id
        };
        

        【讨论】:

        • 对需要更改哪些内容以使代码正常工作的一些解释将对原始发布者和未来用户有所帮助。
        • 使用 FirstOrDefault() 方法,您可以访问任何相关字段,并以简单的方式按您想要的任何字段(usr,角色)进行分组,无需重复数据(完整代码 sn-p )。
        猜你喜欢
        • 2012-10-26
        • 1970-01-01
        • 2023-04-08
        • 1970-01-01
        • 1970-01-01
        • 2016-11-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多