ASP.NET Core 6 MVC中EF关联两主表创建权限详情表的模型类写法
ASP.NET Core 6 MVC + EF Core 用户区域权限模型实现方案
需求回顾
需要通过EF Core创建三个实体模型,对应以下数据库表结构以支持数据库迁移:
- 用户主表(Users):存储用户基础信息
- 区域主表(Areas):存储系统功能区域信息
- 用户区域权限表(UserAreaAuthorizations):关联用户和区域,记录用户是否拥有该区域的访问权限
表结构示例:
-- USERS--- ID Name 1 Tom 2 Jack 3 Smith -- AREAS---- ID Name 10 LOGISTICS 20 FINANCE -- USERAREAAUTHORIZATIONS------------ USERID AREAID IsAuthorized 1 10 FALSE 1 20 TRUE 2 10 TRUE 2 20 FALSE 3 10 TRUE 3 20 TRUE
原代码问题分析
- 字段类型错误:
AppUsers类的Username字段定义为int,但实际需存储字符串类型的用户名(如Tom),类型不匹配 - 导航属性不完整:
AppUsersAuth缺少关联AppUsers的导航属性,EF无法正确识别用户与权限记录的一对多关系 - 主键设计不合理:权限表使用单独的
Id主键,不如用UserId+AreaId复合主键更符合业务唯一性规则 - 属性命名混淆:
AppUsers中的集合属性名AppUsersAuth与类名重复,易引发歧义 - 反向导航缺失:
AppAreas未添加关联权限记录的导航属性,无法从区域维度查询用户权限
修正后的模型代码
namespace App.Models { // 用户实体 public class AppUser { [Key] public int Id { get; set; } // 修正为字符串类型,对应示例中的Name字段 public string Username { get; set; } = string.Empty; public string? FirstName { get; set; } public string? LastName { get; set; } // 关联用户的所有权限记录,重命名避免与类名混淆 public ICollection<UserAreaAuthorization> UserAreaAuthorizations { get; set; } = new List<UserAreaAuthorization>(); } // 用户区域权限实体 public class UserAreaAuthorization { // 使用复合主键:一个用户对一个区域的权限唯一 [Key, Column(Order = 0)] public int UserId { get; set; } [Key, Column(Order = 1)] public int AreaId { get; set; } public bool IsAuthorized { get; set; } // 关联用户实体的导航属性 [ForeignKey(nameof(UserId))] public AppUser AppUser { get; set; } = null!; // 关联区域实体的导航属性 [ForeignKey(nameof(AreaId))] public AppArea AppArea { get; set; } = null!; } // 区域实体 public class AppArea { [Key] public int Id { get; set; } public string Name { get; set; } = string.Empty; // 反向导航:关联该区域的所有用户权限记录 public ICollection<UserAreaAuthorization> UserAreaAuthorizations { get; set; } = new List<UserAreaAuthorization>(); } }
数据库上下文(DbContext)配置
在DbContext中添加DbSet,并可通过Fluent API明确配置关系(显式配置更清晰):
namespace App.Data { public class AppDbContext : DbContext { public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { } public DbSet<AppUser> Users { get; set; } public DbSet<AppArea> Areas { get; set; } public DbSet<UserAreaAuthorization> UserAreaAuthorizations { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { // 配置权限表的复合主键 modelBuilder.Entity<UserAreaAuthorization>() .HasKey(ua => new { ua.UserId, ua.AreaId }); // 配置用户与权限的一对多关系 modelBuilder.Entity<AppUser>() .HasMany(u => u.UserAreaAuthorizations) .WithOne(ua => ua.AppUser) .HasForeignKey(ua => ua.UserId) .OnDelete(DeleteBehavior.Cascade); // 删除用户时自动删除其权限记录 // 配置区域与权限的一对多关系 modelBuilder.Entity<AppArea>() .HasMany(a => a.UserAreaAuthorizations) .WithOne(ua => ua.AppArea) .HasForeignKey(ua => ua.AreaId) .OnDelete(DeleteBehavior.Restrict); // 删除区域时需先清理关联权限 } } }
控制器中的正确使用示例
若需查询用户权限并同时获取区域名称,需使用ThenInclude加载嵌套导航属性:
public class UserAuthorizationController : Controller { private readonly AppDbContext _db; public UserAuthorizationController(AppDbContext db) { _db = db; } // 根据用户ID查询权限详情 public IActionResult Index(int id) { var userWithAuth = _db.Users .Include(u => u.UserAreaAuthorizations) .ThenInclude(ua => ua.AppArea) // 加载权限关联的区域信息 .FirstOrDefault(u => u.Id == id); return View(userWithAuth); } // 查询所有用户的权限列表 public IActionResult List() { var allUsersWithAuth = _db.Users .Include(u => u.UserAreaAuthorizations) .ThenInclude(ua => ua.AppArea) .OrderBy(u => u.Username) .ToList(); return View(allUsersWithAuth); } }
数据库迁移步骤
- 打开包管理器控制台(PMC),执行命令创建迁移:
Add-Migration InitialCreate_UserAreaAuth
- 执行迁移更新数据库:
Update-Database
内容的提问来源于stack exchange,提问作者Joaquim Campos
相关产品推荐
相关产品推荐

