如何通过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
相关产品推荐
相关产品推荐

