基于EF Core 6 Code First实现单表多实体本地化映射问询
EF Core 6 Code First 通用本地化表配置方案
一、自动生成LocalizationKeyId
要实现SomeData插入时自动生成LocalizationKeyId,推荐两种可靠方案:
方式1:数据库层面默认值(优先选择)
通过Fluent API配置数据库自动生成NEWID(),确保无论通过EF还是直接操作数据库插入,都会自动生成唯一Guid:
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<SomeData>() .Property(s => s.LocalizationKeyId) .HasDefaultValueSql("NEWID()"); }
方式2:实体构造函数初始化
在SomeData构造函数中直接赋值,实例化时自动生成Guid:
public class SomeData { public SomeData() { LocalizationKeyId = Guid.NewGuid(); Localizations = new HashSet<Localization>(); } // 其他属性... }
二、配置Localization与SomeData的关联关系
由于Localization是通用表,不能添加指向具体业务表的导航属性,需配置无反向导航的一对多关系,确保Include(s => s.Localizations)能自动加载关联数据:
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<SomeData>() .HasMany(s => s.Localizations) .WithOne() // 无反向导航 .HasForeignKey(l => l.LocalizationKeyId) .HasPrincipalKey(s => s.LocalizationKeyId); // 用SomeData的LocalizationKeyId作为关联主键 }
三、数据完整性约束说明
数据库层面无法给通用Localization表配置跨业务表的外键约束(主流数据库不支持单外键指向多表),可通过以下方式保障数据完整性:
- 给业务表LocalizationKeyId加唯一约束:避免同一Guid被多个业务数据复用
modelBuilder.Entity<SomeData>() .HasIndex(s => s.LocalizationKeyId) .IsUnique();
- 应用层拦截验证:在SaveChanges前检查Localization的KeyId是否存在于任一业务表中
public override int SaveChanges() { var localizationChanges = ChangeTracker.Entries<Localization>() .Where(e => e.State is EntityState.Added or EntityState.Modified); foreach (var entry in localizationChanges) { var keyId = entry.Entity.LocalizationKeyId; // 检查是否存在于SomeData或其他业务表 var isValid = Set<SomeData>().Any(s => s.LocalizationKeyId == keyId); // 后续新增业务表时,追加类似判断:|| Set<OtherData>().Any(o => o.LocalizationKeyId == keyId) if (!isValid) { throw new InvalidOperationException($"LocalizationKeyId {keyId} 未关联任何业务数据"); } } return base.SaveChanges(); }
四、完整OnModelCreating配置示例
protected override void OnModelCreating(ModelBuilder modelBuilder) { // SomeData配置 modelBuilder.Entity<SomeData>(entity => { entity.Property(s => s.LocalizationKeyId) .HasDefaultValueSql("NEWID()"); entity.HasIndex(s => s.LocalizationKeyId) .IsUnique(); entity.HasMany(s => s.Localizations) .WithOne() .HasForeignKey(l => l.LocalizationKeyId) .HasPrincipalKey(s => s.LocalizationKeyId) .OnDelete(DeleteBehavior.Cascade); // 根据业务需求设置删除行为,如Cascade/Restrict }); // Localization与LocalizationLanguage关联配置 modelBuilder.Entity<Localization>(entity => { entity.HasOne(l => l.LocalizationLanguage) .WithMany() // 若LocalizationLanguage有对应导航集合,改为WithMany(ll => ll.Localizations) .HasForeignKey(l => l.LocalizationLanguageId); }); }
内容的提问来源于stack exchange,提问作者Lasse O
相关产品推荐
相关产品推荐

