Linq to 实体组连接多个表
Linq to entities group join on multiple tables
我正在尝试对具有一对多关系的多个 table 执行组加入,使用 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 table 上的连接,并将 into
语句放在 UserRole 上,分组就像一个魅力,但 UserRole 只是一个链接 table,所以角色 table 是我感兴趣的角色。有什么想法可以尽可能简单地对其进行分组吗?谢谢!
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
})
};
导航属性是有原因的。他们使代码更加简洁和声明。
有了导航属性,这会很容易:
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
个属性。如果不是,则不需要 select Role
实体,因为 UserRoles
已经包含 Role
的 Id
.
所以这取决于你。您可以坚持这样的信条,即存储库调用应仅限于一个实体("single responsibility" 的非常狭窄的定义),或者使用导航属性来实现它们的发明目的,并考虑一个聚合根负责它封装的子项。
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
};
我正在尝试对具有一对多关系的多个 table 执行组加入,使用 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 table 上的连接,并将 into
语句放在 UserRole 上,分组就像一个魅力,但 UserRole 只是一个链接 table,所以角色 table 是我感兴趣的角色。有什么想法可以尽可能简单地对其进行分组吗?谢谢!
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
})
};
导航属性是有原因的。他们使代码更加简洁和声明。
有了导航属性,这会很容易:
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
个属性。如果不是,则不需要 select Role
实体,因为 UserRoles
已经包含 Role
的 Id
.
所以这取决于你。您可以坚持这样的信条,即存储库调用应仅限于一个实体("single responsibility" 的非常狭窄的定义),或者使用导航属性来实现它们的发明目的,并考虑一个聚合根负责它封装的子项。
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
};