如何使用EF Core 7 TPC配置获取嵌套结构数据
问题:EF Core中TPC继承下PossibleAnswerCategory的PossibleAnswers集合为空的解决办法
我有如下抽象基类:
public abstract class PossibleAnswerBase { public Uuid Id { get; protected set; } public string Title { get; protected set; } #region Navigation public Uuid QuestionId { get; protected set; } public Question Question { get; } public Uuid? ParentId { get; protected set; } public PossibleAnswerCategory Parent { get; } #endregion protected PossibleAnswerBase() { } }
两个继承类,其中PossibleAnswerCategory支持嵌套结构:
public class PossibleAnswerCategory : PossibleAnswerBase { public ICollection<PossibleAnswerBase> PossibleAnswers { get; private set; } public PossibleAnswerCategory(Uuid id, Uuid? parentId, string title) { Id = id; Title = title; ParentId = parentId; } [UsedImplicitly] private PossibleAnswerCategory() { } } public class PossibleAnswer : PossibleAnswerBase { public PossibleAnswer(Uuid id, string title, Uuid? parentId) { Id = id; Title = title; ParentId = parentId; } }
上下文配置如下:
private void MapQuestionPossibleAnswerBase(ModelBuilder modelBuilder) { var builder = modelBuilder.Entity<PossibleAnswerBase>() .UseTpcMappingStrategy(); builder.HasKey(r => r.Id); builder.Property(r => r.Id).HasColumnName("Id"); builder.Property(r => r.Title).HasColumnName("Title"); builder.Property(r => r.QuestionId).HasColumnName("QuestionId"); builder.Property(r => r.ParentId).HasColumnName("ParentId"); builder.HasOne(pa => pa.Question) .WithMany(q => q.PossibleAnswers) .HasForeignKey(pa => pa.QuestionId); builder.Navigation(pa => pa.Question).AutoInclude(); } private void MapQuestionPossibleAnswerCategory(ModelBuilder modelBuilder) { var builder = modelBuilder.Entity<PossibleAnswerCategory>() .UseTpcMappingStrategy().ToTable("violation_categories"); builder.HasMany(w => w.PossibleAnswers) .WithOne(w => w.Parent) .HasForeignKey(w => w.ParentId); } private void MapQuestionPossibleAnswers(ModelBuilder modelBuilder) { var paBuilder = modelBuilder.Entity<PossibleAnswer>() .UseTpcMappingStrategy().ToTable("violations"); }
现在查询时PossibleAnswerCategory的PossibleAnswers集合始终为空,请问如何配置上下文以正确填充该集合?
解决方案
1. 初始化集合属性
EF Core需要集合实例来填充关联数据,务必在PossibleAnswerCategory的所有构造函数中初始化PossibleAnswers:
public class PossibleAnswerCategory : PossibleAnswerBase { public ICollection<PossibleAnswerBase> PossibleAnswers { get; private set; } public PossibleAnswerCategory(Uuid id, Uuid? parentId, string title) { Id = id; Title = title; ParentId = parentId; PossibleAnswers = new List<PossibleAnswerBase>(); } [UsedImplicitly] private PossibleAnswerCategory() { PossibleAnswers = new List<PossibleAnswerBase>(); } }
2. 修正TPC关联配置
TPC策略下基类与子类表独立,需明确关联的实体类型并配置导航加载:
private void MapQuestionPossibleAnswerCategory(ModelBuilder modelBuilder) { var builder = modelBuilder.Entity<PossibleAnswerCategory>() .ToTable("violation_categories"); // TPC策略已在基类配置,子类无需重复声明 // 明确关联目标为PossibleAnswerBase,设置删除行为 builder.HasMany(c => c.PossibleAnswers) .WithOne(pa => pa.Parent) .HasForeignKey(pa => pa.ParentId) .OnDelete(DeleteBehavior.Restrict); // 开启自动包含,避免每次查询手动Include builder.Navigation(c => c.PossibleAnswers).AutoInclude(); }
3. 补全基类导航属性映射
在基类配置中明确Parent导航的关联关系:
private void MapQuestionPossibleAnswerBase(ModelBuilder modelBuilder) { var builder = modelBuilder.Entity<PossibleAnswerBase>() .UseTpcMappingStrategy(); builder.HasKey(r => r.Id); // ... 原有属性配置 ... builder.HasOne(pa => pa.Question) .WithMany(q => q.PossibleAnswers) .HasForeignKey(pa => pa.QuestionId); // 配置Parent与PossibleAnswers的反向关联 builder.HasOne(pa => pa.Parent) .WithMany(c => c.PossibleAnswers) .HasForeignKey(pa => pa.ParentId) .IsRequired(false); // ParentId可空,关联设为非必需 builder.Navigation(pa => pa.Question).AutoInclude(); }
4. 查询时显式Include(可选)
若自动包含未生效,可在查询时手动指定加载集合:
var categories = await _context.Set<PossibleAnswerCategory>() .Include(c => c.PossibleAnswers) .ToListAsync();
内容的提问来源于stack exchange,提问作者Fallingsappy
相关产品推荐
相关产品推荐

