具有相关 ViewModel DTO C# 的多对多

问题描述 投票:0回答:6

我在 NetCore C# 项目中有 3 个表,我无法对数据库进行查询以形成附加角色的用户的完整列表

用户表

var user = await _context.Users
    .Select(x => new
    {
        x.Id,
        x.UserName           
    }).ToListAsync();

角色表

var role = await _context.Roles
    .Select(x => new
    {
        RoleId = x.Id,
        RoleName = x.Name
    }).ToListAsync();

和UserRole表(关系)

var userRole = await _context.UserRoles
    .Select(x => new
    {
        x.RoleId,
        x.UserId
    }).ToListAsync();

您需要如何构建查询来生成此 DTO?

public class UserRoleDto
{
    public int UserId { get; set; }
    public string UserName { get; set; }

    public IEnumerable<RolesDto> Roles { get; set; }

}

public class RolesDto
{
    public int RoleId { get; set; }

    public string RoleName { get; set; }
}

并且显示了这个结果?

[
    {
        "userId": "1",
        "userName": "User1",
        "roles": [
            {
                "roleId": "1",
                "roleName": "admin"
            },
            {
                "roleId": "2",
                "roleName": "operator"
            },
            {
                "roleId": "3",
                "roleName": "support"
            }
        ]
    },
    {
        "userId": "2",
        "userName": "User2",
        "roles": [
            {
                "roleId": "2",
                "roleName": "operator"
            }
        ]
    }
]
c# entity-framework asp.net-core .net-core entity-framework-core
6个回答
1
投票

考虑不包括 -

public DbSet<UserRole> UserRoles { get; set; }

在你的

DbContext
课堂上。这是因为
UserRole
是一个连接实体,而连接实体不是以模型为中心的概念。它们的存在纯粹是一种以关系数据库为中心的想法。因此,尽量不要直接针对加入实体进行查询。

将模型定义为 -

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }

    public IList<UserRole> UserRoles { get; set; }
}

public class Role
{
    public int Id { get; set; }
    public string Name { get; set; }

    public IList<UserRole> UserRoles { get; set; }
}

public class UserRole
{
    public int UserId { get; set; }
    public int RoleId { get; set; }

    public User User { get; set; }
    public Role Role { get; set; }  
}

您的查询可以是这样的 -

var result = await _context.Users.Select(
    u => new UserRoleDto
    {
        UserId = u.Id,
        UserName = u.Name,
        Roles = u.UserRoles.Select(x => new RolesDto { RoleId = x.RoleId, RoleName = x.Role.Name }).ToList()
    }).ToListAsync();

0
投票

我对此的第一印象是您的连接表 UserRole 可能如下所示:

public class UserRole
{
    public int UserId {get; set;}
    public int RoleId {get; set;}
}

这很好,但它缺乏满足 DTO 要求的导航属性。 您的目标应该是建立一个连接表

public class UserRole
{
    public int UserId {get; set;}
    public int RoleId {get; set;}
    public Role Role {get; set;}
    public User User {get; set;}
}

你几乎得到了正确的查询,它没有经过测试,但尝试这样的事情:

var userRole = await _context.UserRoles
    .Select(x => new UserRoleDto()  
    {
       UserId = x.User.Id,
       UserName = x.User.Name,
       Roles = new List<RolesDto>()
       {
           new RolesDto()
           {
              RoleId = x.Role.Id,
              RoleName = x.Role.Name
           }
       }
    }).ToListAsync();

0
投票

改变

public class UserRoleDto
{
    public int UserId { get; set; }
    public string UserName { get; set; }

    public IEnumerable<RolesDto> Roles { get; set; }

}

public class UserRoleDto
{
    public int UserId { get; set; }
   
 public int RoleId{ get; set; }
}

并进行查询以连接用户和角色。之后使用这篇文章从结构化数据构建 JSON 层次结构转换为 json。


0
投票

可以在 OnModelCreating 中配置多对多

modelBuilder.Entity<User>()
   .HasMany(b => b.Roles)
   .WithMany(c => c.Users)
   .Map(cs =>
   {
       cs.MapLeftKey("UserId");
       cs.MapRightKey("RoleId");
       cs.ToTable("UserToRole");
   });

0
投票

我用给定的解决方案实现了它

var users = await _context.Users.Select(x => new { x.Id, x.UserName }).ToListAsync();
var userRoles = await _context.UserRoles.ToListAsync();
var roles = await _context.Roles.ToListAsync();

var result = users.Select(x => new
{
    UserId = x.Id,
    x.UserName,
    Roles = userRoles
        .Where(y => y.UserId == x.Id)
        .Join(roles, r => r.RoleId, r => r.Id, (u, r) => new
        {
            RoleId = r.Id,
            RoleName = r.Name
        }).ToList()
    }); 
return Ok(result);

0
投票

您应该考虑使用 c# AutoMapper 在您的项目中映射此类结果。

就我而言,我在 .netCore 中有以下查询:

 List<GrelhaTamanhos> grelhaTamanhos = await _context.GrelhasTamanhos
            .Include(x => x.GrelhaTamanhosTamanhos)
            .ThenInclude(x => x.Tamanho)
            .Where(x => x.Id == id).FirstOrDefaultAsync();

然后我就使用 Automapper:

GrelhaTamanhosDTO grelhaTamanhosDTO = _mapper.Map<GrelhaTamanhosDTO>(grelhaTamanhos);

我的结果是 GrelhaTamanhosDTO 的对象,其中包含 Tamanhos 列表。

查看 AutoMapper 的文档,它是一个很棒的工具。

© www.soinside.com 2019 - 2024. All rights reserved.