EF Core 3.1:父子实体映射至单数据库表的配置问题
解决方案
要在EF Core 3.1中将你的Parent和Child实体映射到指定的扁平化单表,同时保留实体关联,可通过**拥有实体(Owned Entities)**结合无表实体配置实现,具体步骤如下:
1. 实体类保持不变
你的实体类无需修改,继续使用原结构:
public class Parent { public int Id { get; set; } public string Name { get; set; } public virtual ICollection<Child> Children { get; set; } } public class Child { public int Id { get; set; } public string Name { get; set; } public int ParentId { get; set; } public virtual Parent Parent { get; set; } }
2. DbContext配置
在你的DbContext中,通过Fluent API完成表映射和实体关联配置:
public class YourDbContext : DbContext { public DbSet<Parent> Parents { get; set; } public DbSet<Child> Children { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { // 配置你的数据库连接字符串 optionsBuilder.UseSqlServer("YourConnectionString"); } protected override void OnModelCreating(ModelBuilder modelBuilder) { // 配置Child实体映射到目标表 modelBuilder.Entity<Child>(childBuilder => { // 指定表名 childBuilder.ToTable("ParentChild"); // 设置Child的主键 childBuilder.HasKey(c => c.Id); // 映射Child属性到表列 childBuilder.Property(c => c.Name).HasColumnName("ChildName"); childBuilder.Property(c => c.ParentId).HasColumnName("ParentId"); // 将Parent配置为Child的拥有实体,映射到表的对应列 childBuilder.OwnsOne(c => c.Parent, parentBuilder => { parentBuilder.Property(p => p.Id) .HasColumnName("ParentId") .ValueGeneratedNever(); // 禁止自动生成,使用Child的ParentId值 parentBuilder.Property(p => p.Name).HasColumnName("ParentName"); }); }); // 配置Parent为无表实体,通过Child表聚合数据 modelBuilder.Entity<Parent>(parentBuilder => { // 无表实体无需主键(或可指定逻辑主键) parentBuilder.HasNoKey(); // 标记为无表,使用LINQ查询从Child表聚合 parentBuilder.ToView(null); // 映射Parent属性到表列 parentBuilder.Property(p => p.Id).HasColumnName("ParentId"); parentBuilder.Property(p => p.Name).HasColumnName("ParentName"); // 配置Parent与Child的一对多关联 parentBuilder.HasMany(p => p.Children) .WithOne(c => c.Parent) .HasForeignKey(c => c.ParentId); }); } }
3. 数据操作示例
插入数据
由于Parent信息存储在Child行中,插入时需通过Child实体操作:
using var context = new YourDbContext(); var parent = new Parent { Id = 1, Name = "父实体1" }; var child1 = new Child { Id = 1, Name = "子实体1", ParentId = 1, Parent = parent }; var child2 = new Child { Id = 2, Name = "子实体2", ParentId = 1, Parent = parent }; context.Children.AddRange(child1, child2); context.SaveChanges();
查询数据
查询Parent时可直接关联获取对应的Children集合:
using var context = new YourDbContext(); var parentsWithChildren = context.Parents .Include(p => p.Children) .ToList();
注意事项
- 由于采用反规范化存储,修改Parent的信息(如Name)时,需要手动更新所有关联Child行的
ParentName列,或通过数据库触发器自动同步。 - 此方案利用EF Core 3.1支持的拥有实体特性替代ComplexType,符合版本限制要求。
内容的提问来源于stack exchange,提问作者Nicolas Boisvert
相关产品推荐
相关产品推荐

