我需要在EF6
中的多对多关系中从连接表返回单个列User { Id, Name}
Role { Id, Role}
UserToRole { UserId, RoleId}
这是一个简化的示例,但我需要从User获取RoleId(Role.Id)的列表。
理想情况下,我只是做一些像
这样的事情context.UserToRole.Where(x => x.UserId == id).Select(r => r.RoleId).ToList();
但EF似乎并没有向我提供该联接表作为查询对象。
我知道我可以将所有角色作为对象拉下来,但在我的实际系统中,这是一个宽表,我想避免将所有数据拉到线上并将其放入内存的开销
答案 0 :(得分:5)
如果您只需要RolesId
中的User
,则可以执行此查询:
int userId=1;
var roleIds = db.Users.Where(u => u.Id == userId).SelectMany(u => u.Roles.Select(a=>a.Id));
这将生成如下的SQL查询:
{SELECT [Extent1].[Role_Id] AS [Role_Id]
FROM [dbo].[UserRoles] AS [Extent1]
WHERE [Extent1].[User_Id] = @p__linq__0}
正如您所看到的,您所查找的查询是相同的。
答案 1 :(得分:1)
您可以尝试context.Roles.SqlQuery("Select * from Roles where id in (select roleid from usertoroles where userid = @userid")
以避免加载用户。
如果您的问题是将所有角色分配给特定用户,请按如下所示定义您的实体:
public class User
{
public int Id { get; set; }
public string UserName { get; set; }
//Navigation Property
public List<Role> Roles { get; set; }
}
public class Role
{
public int Id { get; set; }
public string Name { get; set; }
//Navigation Property
public List<User> Users { get; set; }
}
除非您想要控制多个表名和列名(这很简单),否则您已经完成了设置。
创建用户
User k = new User()
{
UserName = "Kishan",
Roles = new List<Role>()
{
new Role() { Name = "Supremo" }
}
}
context.Users.Add(u);
context.SaveChanges();
User r = new User()
{
UserName = "Rama",
Roles = new List<Role>()
{
context.Roles.Single(r => r.Name == "Supremo")
}
}
context.SaveChanges();
为用户查找角色
User u = context.Users.Single(u => u.UserName == "Kishan");
List<int> userRoleIdList = u.Roles.Select(r => r.Id).ToList();
答案 2 :(得分:0)
关系应该已经存在:通常,如果你将多对多关系定义为两种方式的集合,EF将为你生成连接表,这意味着你必须聪明地制作你的LINQ查询就你可以看到的表而言(有时可能有点棘手)。 (我从你的评论中看出“EF似乎没有为你提供联接表”,确实如此。)
所以,根据你给出的例子,它将是这样的:
context.Users.Where(u => u.Id == id).Single().Roles.Select(r => r.Id);
但需要注意的是,如果找不到User
Id==id
或者找不到多个Id
,则会抛出此内容(因此{{1}}不是密钥)。但是,这通常就是您想要的查找方式。