我正在尝试使用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表是我感兴趣的表in。任何想法如何尽可能简单地分组?谢谢!
答案 0 :(得分:2)
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
})
};
答案 1 :(得分:1)
导航属性是有原因的。它们使代码变得更加简洁和声明。
使用导航属性这很容易:
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
(你似乎没有使用它),但是如果你需要它,你应该在那里开始查询并使用导航属性来到其他实体。
另外,我假设您在Role
中有更多RoleDto
个属性。如果没有,则您不需要选择Role
个实体,因为UserRoles
已包含Role
&#39; s Id
。
所以它取决于你。您可以坚持信条,即存储库调用应限定为一个实体(一个非常狭窄的定义&#34;单一责任&#34;),或者使用导航属性来实现它们的发明,并考虑一个聚合root负责它封装的孩子。
答案 2 :(得分:-1)
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
};