You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过DbContext重写Patient实体插入逻辑,拆分至子表并保留视图查询

方案合理性说明

你的方案完全不是多此一举,反而很实用:

  • 数据库级权限管控:可以给普通用户仅分配patient视图的查询权限,禁止其直接访问patient_info表,后续在patient_info新增的敏感属性(比如病史、联系方式)不会被无权限用户看到,比应用层控制更可靠。
  • 数据职责拆分:将患者基础信息与证件信息分开存储,符合单一职责原则,后续扩展其他证件类型或基础属性时,不会互相影响。
  • 上层解耦:应用层统一通过Patient实体交互,无需感知底层两张表的结构,降低代码耦合度。
EF Core具体实现步骤

1. 定义实体类

// 对应patient视图的实体,用于查询
public class Patient
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string PassportData { get; set; }
}

// 对应patient_info表的实体
public class PatientInfo
{
    public int Id { get; set; }
    public string Name { get; set; }
    // 后续可添加敏感属性,比如:
    // public string MedicalHistory { get; set; }
}

// 对应patient_documents表的实体
public class PatientDocuments
{
    public int DocumentsId { get; set; }
    public int PatientId { get; set; }
    public string PassportData { get; set; }
}

2. 配置DbContext

在你的DbContext子类中,配置实体与数据库对象的映射,以及表之间的关系:

public class YourDbContext : DbContext
{
    // 用于查询的Patient视图
    public DbSet<Patient> Patients { get; set; }
    // 底层表的DbSet
    public DbSet<PatientInfo> PatientInfos { get; set; }
    public DbSet<PatientDocuments> PatientDocuments { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        // 配置你的数据库连接字符串
        optionsBuilder.UseMySQL("your_connection_string");
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // 映射Patient到patient视图,设置主键(视图的Id唯一)
        modelBuilder.Entity<Patient>()
            .ToView("patient")
            .HasKey(p => p.Id);

        // 禁止Patient实体的插入/更新/删除操作(避免误操作)
        modelBuilder.Entity<Patient>()
            .HasNoInsert()
            .HasNoUpdate()
            .HasNoDelete();

        // 配置PatientInfo与patient_info表的映射
        modelBuilder.Entity<PatientInfo>()
            .ToTable("patient_info")
            .HasKey(p => p.Id);

        // 配置PatientDocuments与patient_documents表的映射,以及和PatientInfo的一对一关系
        modelBuilder.Entity<PatientDocuments>()
            .ToTable("patient_documents")
            .HasKey(p => p.DocumentsId);
        modelBuilder.Entity<PatientDocuments>()
            .HasOne<PatientInfo>()
            .WithOne()
            .HasForeignKey<PatientDocuments>(p => p.PatientId)
            .IsRequired();
    }
}

3. 实现自定义添加逻辑

在DbContext中添加专门的方法,用于将Patient实体拆分插入到两张底层表:

public void AddPatient(Patient patient)
{
    // 1. 插入patient_info表,获取自增的Id
    var patientInfo = new PatientInfo
    {
        Name = patient.Name
    };
    PatientInfos.Add(patientInfo);
    SaveChanges(); // 先保存以生成Id

    // 2. 插入patient_documents表,关联刚生成的PatientId
    var patientDocuments = new PatientDocuments
    {
        PatientId = patientInfo.Id,
        PassportData = patient.PassportData
    };
    PatientDocuments.Add(patientDocuments);
    SaveChanges();
}

4. 使用方式

  • 查询患者:直接从视图读取,和原有逻辑一致:
    using var db = new YourDbContext();
    var patients = db.Patients.ToList();
    
  • 添加患者:调用自定义的AddPatient方法:
    using var db = new YourDbContext();
    var newPatient = new Patient
    {
        Name = "张三",
        PassportData = "110101199001011234"
    };
    db.AddPatient(newPatient);
    

补充说明

如果使用的是EF Core 7以下版本,不支持HasNoInsert()等方法,可以重写SaveChanges来拦截Patient实体的修改操作:

public override int SaveChanges(bool acceptAllChangesOnSuccess)
{
    // 将所有Patient实体的状态设为Unchanged,禁止插入/更新/删除
    foreach (var entry in ChangeTracker.Entries<Patient>())
    {
        entry.State = EntityState.Unchanged;
    }
    return base.SaveChanges(acceptAllChangesOnSuccess);
}

内容的提问来源于stack exchange,提问作者IT demon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 09:12:06