如何从LINQ获得一对多的SingleOrDefault值?

Sam*_*tar 0 c# linq asp.net asp.net-identity

我有两个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; }
}
Run Code Online (Sandbox Code Playgroud)

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; }
}
Run Code Online (Sandbox Code Playgroud)

我有这个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();
Run Code Online (Sandbox Code Playgroud)

但这给了我两个错误,在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.

小智 5

有一些问题.让我们从给出编译时错误的那个开始.

RoleSingleId = u.AspNetRoles.SingleOrDefault(r => r.Id),
Run Code Online (Sandbox Code Playgroud)

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相同的方式调整类型.