我有两个ASP.NET标识使用的类。一个是用户列表的支持类,另一个是角色。在数据库中有三个表。 AspNetUsers,AspNetRoles和AspNetUserRoles。由于它们在实体框架中的映射方式,这三个映射到两个类:
public partial class AspNetUser
{
public AspNetUser()
{
this.AspNetUserClaims = new List<AspNetUserClaim>();
this.AspNetUserLogins = new List<AspNetUserLogin>();
this.AspNetRoles = new List<AspNetRole>();
}
public int Id { get; set; }
public virtual ICollection<AspNetRole> AspNetRoles { get; set; }
public virtual ICollection<AspNetUserClaim> AspNetUserClaims { get; set; }
public virtual ICollection<AspNetUserLogin> AspNetUserLogins { get; set; }
}
和
public partial class AspNetRole
{
public AspNetRole()
{
this.AspNetUsers = new List<AspNetUser>();
}
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<AspNetUser> AspNetUsers { get; set; }
}
我有这个LINQ语句用于报告数据。请注意,我只想获得与用户关联的第一个角色。这是我试过的:
var user = await db.AspNetUsers
.Where(u => u.AspNetRoles.Any(r => r.Id == roleId) || roleId == 0)
.Include(u => u.AspNetRoles)
.Select(u => new UserDTO
{
Email = u.Email,
RoleSingleId = u.AspNetRoles.SingleOrDefault(r => r.Id),
UserId = u.Id,
UserName = u.UserName
})
.ToListAsync();
但是这给了我两个错误,在r.Id
下有一条蓝线错误4无法将lambda表达式转换为委托类型'System.Func',因为某些返回类型 在块中不能隐式转换为委托返回类型
错误5无法将类型'int'隐式转换为'bool'C:\ App \ ab41 \ Admin1 \ WebRole1 \ Controllers \ Web API - Data \ UserController.cs 169 71 WebRole1
注意RoleSingleId声明为int,AspNetRoles的Id也是int。
答案 0 :(得分:5)
有一些问题。让我们从给出编译时错误的那个开始。
RoleSingleId = u.AspNetRoles.SingleOrDefault(r => r.Id),
SingleOrDefault
采用谓词,而不是投射。您作为参数传递的是一个条件,它告诉您是否应该考虑指定的AspNetRole
。它是u.AspNetRoles.Where(r => r.Id).SingleOrDefault()
的缩写。
这不是你想要的。投影是使用Select
完成的,而不是Where
,因此可以通过将其写为u.AspNetRoles.Select(r => r.Id).SingleOrDefault()
来修复该部分。
一旦你解决了这个问题,下一个问题就是SingleOrDefault()
被设计为在找到多个项目时抛出异常。这不是你想要的。您说您希望返回其中一个角色ID。那是FirstOrDefault()
。
第三个问题是,SingleOrDefault()
通常在查询中通常不受支持。它将进行编译,但无论用户拥有多少角色,它都会在运行时抛出异常,告诉您它只是不理解如何执行此操作,并且您可能希望使用FirstOrDefault()
。由于FirstOrDefault()
是你应该使用的,所以这不是问题。
注意:您可能还想将Select(r => r.Id)
更改为Select(r => (int?)r.Id)
:前者返回IEnumerable<int>
,后者返回IEnumerable<int?>
。如果用户没有角色(如果它完全有效),FirstOrDefault()
将返回前者0
,后者null
。null
。RoleSingleId
{{1}}这里可能更有意义。您需要以相同的方式调整{{1}}的类型。
答案 1 :(得分:1)
如果您使用SelectMany而不是Select,那么您的返回将像传统的SQL语句一样扁平化。即,将为该用户的每个角色重复用户详细信息。
获取单个或默认用户/角色将如下所示:
var user = await db.AspNetUsers
.Where(u => u.AspNetRoles.Any(r => r.Id == roleId) || roleId == 0)
.Include(u => u.AspNetRoles)
.SelectMany(u => new UserDTO
{
Email = u.Email,
RoleSingleId = u.AspNetRoles.Id,
UserId = u.Id,
UserName = u.UserName
})
.SingleOrDefault();
当然,如果您正在尝试获取针对每个用户的第一个角色列表,那么您将需要GroupBy用户ID,用户名和电子邮件,以某种方式聚合角色ID(例如获取最大值)每个用户的价值)。
即
var user = await db.AspNetUsers
.Where(u => u.AspNetRoles.Any(r => r.Id == roleId) || roleId == 0)
.Include(u => u.AspNetRoles)
.SelectMany(u => new UserDTO
{
Email = u.Email,
RoleSingleId = u.AspNetRoles.Id,
UserId = u.Id,
UserName = u.UserName
})
.GroupBy(key => new { key.Email, key.UserId, key.UserName },
(key, agg) => new UserDTO
{
Email = key.Email,
UserId = key.Id,
UserName = key.UserName,
RoleSingleId = agg.Max(a => a.RoleSingleId),
})
.ToListAsync();