我在 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"
}
]
}
]
考虑不包括 -
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();
我对此的第一印象是您的连接表 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();
改变
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。
可以在 OnModelCreating 中配置多对多
modelBuilder.Entity<User>()
.HasMany(b => b.Roles)
.WithMany(c => c.Users)
.Map(cs =>
{
cs.MapLeftKey("UserId");
cs.MapRightKey("RoleId");
cs.ToTable("UserToRole");
});
我用给定的解决方案实现了它
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);
您应该考虑使用 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 的文档,它是一个很棒的工具。