在我的ASP.NET MVC 5应用程序中,我想列出用户的角色。我下载了一些似乎坏了的样本。基本上,我想要所选用户(而不是当前用户!)角色的角色ID和角色名称。
Roles为我提供了一个只有RoleId和UserId的IdentityUserRole对象。
Roles为我提供了一个Identity Role,其中包含所有应用程序角色的RoleId、RoleName等。
因此,我想要的是一个包含两个集合交集的结果集,同时保留完整的角色信息,这样我就可以同时使用它的角色ID和角色名称。
我尝试过Intersect(),但没有成功,因为两个对象的类型不同。我尝试了愚蠢的迭代风格,但得到了一个异常,说DAta阅读器已经激活了,所以我被难住了:(
我在LinQPad上尝试了以下操作(使用适当的功能和名称空间):
string UserName = "user@email.com";
ApplicationDbContext ctx = new ApplicationDbContext();
var allroles = ctx.Roles.OrderBy(r => r.Id);
allroles.Dump(); // dumps well, 6 roles
ApplicationUser user = ctx.Users.Where(u => u.UserName.Equals(UserName, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
var myroles = user.Roles;
myroles.Dump(); // dumps well, 3 roles
IEnumerable<IdentityRole> list = from roles in allroles
join uroles in myroles
on roles.Id equals uroles.RoleId
select roles;
list.Dump(); // exception
虽然查询在执行过程中似乎不会产生错误,但无论我使用Dump()还是显式foreach(列表中的IdentityRole项),它的转储都会产生错误。在这种情况下,我得到的错误是
"无法创建类型为"Microsoft.AspNet.Identity.EntityFramework.IdentityUserRole"的常数值。此上下文中仅支持基元类型或枚举类型"。
这里唯一的问题是,您没有调用立即执行查询的ToList()
方法(所有内容都将保存在内存中)。
为了更好地理解,ToList()
方法将IEnumerable<T>
转换为List<T>
。
因此,您的代码将如下所示:
var allroles = ctx.Roles.OrderBy(r => r.Id).ToList();
var myroles = user.Roles.ToList();
您可以使用尝试过的两种方法的组合,从ApplicationUser
的Roles
属性中存在的上下文中获取角色。。。
var roles = ApplicationDbContext.Roles
.Where(ar =>
ApplicationUser.Roles
.Select(ur =>
ur.RoleId)
.Contains(ar.RoleId));
您可以这样做:
var rolesList = allroles.ToList().Join(myroles.ToList(),
left => left.Id,
right => right.RoleId,
(left,right) => left);
这种方式适用于不同的场景。
您正试图将内存中的列表myroles
与IQueryable
、allroles
连接,从而生成新的IQueryable
:list
。但是,这个新的IQueryable
被翻译成SQL,所以myroles
也必须被翻译成SQL。非基元类型的列表不支持此操作。
解决方案是加入两个IQueryable
:
var myroles = ctx.Users.Where(u => u.UserName == UserName).SelectMany(u => u.Roles);
var list = from role in allroles
join urole in myroles
on role.Id equals urole.RoleId
select role;