DncZeus实战开源项目(四)数据库设计

// dbContext.cs
......
protected override void OnModelCreating(ModelBuilder modelBuilder)
{

    modelBuilder.Entity<DncPermission>(entity =>
    {
        // 设置权限Code为唯一索引
        entity.HasIndex(x => x.Code).IsUnique();
        /*
        物理层面:Permission (1) ←→ (1) Menu  (一对一记录)
        业务层面:Menu (1) ←→ (*) Permission  (一对多)
        */
        entity.HasOne(x => x.Menu).WithMany(x => x.Permissions).HasForeignKey(x => x.MenuGuid);
    });

    base.OnModelCreating(modelBuilder);
}

表关系的正确理解

1. 物理表关系:一对一

数据库表层面看,这确实是一对一关系

DncPermission 表        DncMenu 表
-----------------     ------------
PermissionId (PK)      MenuId (PK)  
MenuGuid (FK)  ←→     Id (PK)

每个权限记录只能属于一个菜单(通过外键 MenuGuid),这就是物理表的一对一关系。

2. 业务逻辑关系:一对多

业务对象层面看,这是一对多关系

  • 一个菜单 可以有多个权限
  • 一个权限 只能属于一个菜单

3. 混淆的根源:来自于两个不同层面的视角

错误理解:

  • 认为表关系应该是"一对多"
  • 但实际上每个权限记录只能关联一个菜单记录

正确理解:

业务层面:Menu (1) ←→ (*) Permission  (一对多)
物理层面:Permission (1) ←→ (1) Menu  (一对一记录)

4. 具体示例说明

数据示例:

-- DncMenu 表
MenuId    MenuName
1         用户管理
2         系统设置

-- DncPermission 表  
PermissionId  PermissionCode    MenuGuid
101           user.view         1
102           user.edit         1
103           system.config     2

关系解释:

  • 菜单"用户管理"(ID=1) 有两个权限:查看、编辑
  • 每个权限记录只能指向一个菜单记录
  • 这就是一对多关系通过外键实现一对一物理连接

5. EF Core 代码映射

// 在 Menu 实体中
public class DncMenu
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    
    // 一个菜单有多个权限
    public ICollection<DncPermission> Permissions { get; set; }
}

// 在 Permission 实体中  
public class DncPermission
{
    public Guid Id { get; set; }
    public string Code { get; set; }
    
    // 一个权限属于一个菜单
    public Guid MenuGuid { get; set; }
    public DncMenu Menu { get; set; }
}

6. 总结

不会造成混乱的原因:

  1. 物理层面:每条权限记录只关联一条菜单记录(一对一)
  2. 逻辑层面:从菜单角度可以找到多个权限(一对多)
  3. 外键约束:保证了数据完整性

这是关系数据库中标准的一对多关系实现方式,通过在"多"的一方添加外键指向"一"的一方来实现。

我来为你画一个 Mermaid 图来理清物理关系和业务逻辑关系:

erDiagram %% 业务逻辑关系(概念层) DncMenu { Guid Id "主键" string Name "菜单名称" string Icon "图标" int Sort "排序" } DncPermission { Guid Id "主键" string Code "权限代码" string Name "权限名称" Guid MenuGuid "外键" } %% 物理表关系(数据层) %% 一对多关系通过外键实现 DncMenu ||--o{ DncPermission : "1对多(业务层)" %% 每个权限记录只能指向一个菜单记录 DncPermission }o--|| DncMenu : "1对1(物理层)"
classDiagram %% 业务对象模型 class DncMenu { +Guid Id +string Name +string Icon +int Sort +ICollection~DncPermission~ Permissions +GetPermissions() List~DncPermission~ } class DncPermission { +Guid Id +string Code +string Name +Guid MenuGuid +DncMenu Menu +GetMenu() DncMenu } %% 业务关系:一对多 DncMenu "1" *-- "*" DncPermission : 业务逻辑关系 note for DncMenu "一个菜单可以有多个权限" note for DncPermission "一个权限只能属于一个菜单"
graph LR subgraph "物理数据库层面" M1[菜单表记录1<br/>用户管理] M2[菜单表记录2<br/>系统设置] P1[权限记录1<br/>user.view] P2[权限记录2<br/>user.edit] P3[权限记录3<br/>system.config] M1 --> P1 M1 --> P2 M2 --> P3 end subgraph "业务逻辑层面" UserMenu[用户管理菜单] SystemMenu[系统设置菜单] UserMenu --> |包含| ViewPerm[查看权限] UserMenu --> |包含| EditPerm[编辑权限] SystemMenu --> |包含| ConfigPerm[配置权限] end style M1 fill:#e1f5fe style M2 fill:#e1f5fe style P1 fill:#f3e5f5 style P2 fill:#f3e5f5 style P3 fill:#f3e5f5

3. 关系总结

  • 数据库设计:在权限表中添加外键指向菜单表(标准的一对多实现)
  • 查询方式:从菜单找权限是"一对多",从权限找菜单是"一对一"
  • 本质:这是关系数据库中标准的一对多关系模式,没有混乱
posted @ 2025-12-18 11:47  清安宁  阅读(2)  评论(0)    收藏  举报