所以你有Users 和UserRoles。 Users 和 UserRoles 之间存在一对多的关系:每个 User 都有零个或多个 UserRoles;每个 UserRole 只属于一个 User,即外键 UserId 所指的 User。
您也有一个用户名,并且您希望所有用户都有这个名称,每个用户都有自己的用户角色。
注意:您并没有说 UserName 是唯一的,所以在 Where 之后您仍然有几个用户名为“Will Smith”的用户。
简答
string userName = "Will Smith";
var result = dbContext.Users
.Where(user => user.UserName == userName)
.Join(dbContext.UserRoles,
user => user.Id, // from each User take the Id
userRole => userRole.UserId, // from each UserRole take the foreign key
(user, userRole) => userRole);
或者反过来:从 UserRoles 开始,只保留那些拥有 aUser 和 userName 的 UserRoles:
dbContext.UserRoles.Where (userRole =>
dbContext.Users
.Where(user => user.Id == userRole.UserId // get the User of this Role
&& user.UserName == userName) // check the name of this User
.Any() );
还有改进的余地
如果用户 [10] 有 20 个用户角色,那么用户 [10] 的每个用户角色都将有一个值为 10 的外键。您将传输此值 20 次。
如果有多个“Will Smith”,您将拥有一个大序列,其中所有“Will Smiths”的所有 UserRole 随机混合。
您的解决方案将导致:
UserId UserRole
10 Administator,
10 User
25 Backup
10 Backup
18 User
25 User
对用户进行分组不是更有效吗,所以你有类似的东西:
UserId UserRoles
10 { Administator, User, Backup }
18 { User }
25 { User, Backup }
22 <no UserRoles yet>
注意:结果略有不同:您还获得了还没有角色的用户。
当您的项目具有零个或多个子项目时,例如具有学生的学校、具有订单的客户或具有用户角色的用户,请考虑使用 Queryable.GroupJoin 的重载之一。
大多数时候我使用带有参数 resultSelector 的重载。这样您就可以准确地指定您想要的属性以及格式:
var usersWithTheirUserRoles = dbContext.Users
// keep only the users with a specific UserName
.Where(user => user.UserName == userName)
// fetch some properties of the remaining users and their UserRoles
.GroupJoin(dbContext.UserRoles,
user => user.Id, // from each User take the Id
userRole => userRole.UserId, // from each UserRole take the foreign key
// parameter resultSelector: take each user, with its zero or more userRoles
// to make one new:
(user, userRolesOfThisUser) => new
{
// Select only the user parameters that you plan to use:
Id = user.Id,
Address = user.Address,
...
// select the zero or more user roles of this user
UserRoles = userRolesOfThisUser.Select(userRole => new
{
// Select only the properties that you plan to use
Id = userRole.Id,
Description = userRole.Description,
...
// not needed, you've already got the value:
// UserId = userRole.UserId,
})
.ToList(),
});
优点:
- 您还可以获得尚未拥有 UserRoles 的用户(在您的原始要求中没有问题)
- 效率:用户的每个属性只发送一次。内连接或左外连接会一遍又一遍地发送用户的相同属性
- 效率:您只传输您真正需要的属性
- 您可以偏离原始表格。如果你想省略 UserRoles,或者计算一些属性,比如
UserRoleCount,你可以这样做。这样可以更轻松地在未来更改您的数据库表,而无需更改此查询