EF Core Fluent API 配置可防止 TPC 继承



我有相互继承的模型,但我正在努力让流畅的 api 配置按照我想要的方式运行。假设我有一个基类,它定义了一些核心属性

public class Entity
{
public int Id { get; set; }
public string Title { get; set };
}

和书籍的子类

public class Book : Entity
{
public int Edition { get; set; }
}

这样,我就可以拥有书籍、杂志、小册子、漫画、演讲等,所有这些都继承自我的实体,而不必定义每个类的关系。

现在,我将我的 DbSet 添加到 DbContext 中,如下所示

public class ApplicationDbContext : DbContext
{
public virtual DbSet<Book> Books { get; set; }
public virtual DbSet<Magazine> Magazines { get; set; }
public virtual DbSet<Comic> Comics { get; set; }
}

最后,我添加了迁移初始。

我的迁移现在为每种类型创建单独的表 (TPC)。完善。

当我尝试使用流畅的 API 配置基类时,问题就来了。

我为实体添加配置

class EntityConfiguration : IEntityTypeConfiguration<Entity>
{
public void Configure(EntityTypeBuilder<Entity> builder)
{
builder.HasKey(e => e.Id);
builder.Property(e => e.Title).IsRequired();
}
} 

这个想法是我现在只需要配置基本实体,子类的所有表都应该选择配置。

我将我的配置添加到 DbContext OnModelCreate 方法中。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfiguration(new EntityConfiguration());
}

当我添加迁移时,我最终会得到这个

migrationBuilder.CreateTable(
name: "Entity",
columns: table => new
{
Edition = table.Column<int>(nullable: true),
Name = table.Column<string>(nullable: true),
Id = table.Column<int>(nullable: false)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
Discriminator = table.Column<string>(nullable: false),
Title = table.Column<string>(nullable: false),
Frequency = table.Column<int>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Entity", x => x.Id);
});

通过尝试配置基类,EF 现在正在沿着 TPH 路由前进,并为具有鉴别器列的实体创建单个表。

有没有办法避免这种情况?甚至是否可以配置基类并让所有具体表选取基类上的配置,但为子类创建表?

注意:我尝试直接在 DbContext OnModelCreate 方法中配置实体,而不是使用单独的配置类,但这的行为是一样的。

EF Core 文档实际上说不支持 TPC,这很奇怪,因为它确实为子类创建了单独的表,直到我尝试配置基类。

我尝试使用 Ignore() 来抑制 TPH,但这没有效果。

给出的例子不是现实世界。我的实际项目有更多的类,它们都具有共同的属性和关系,所以我想避免一遍又一遍地配置相同的东西。

您说得对,EF Core在撰写本文时不支持TPC。

但是,似乎确实有一种方法可以解决这个问题(至少用于生成"Up"脚本)。

删除FluentAPI注册,并对实体类的属性使用Annotations

public abstract class Entity
{
[Key]
public int Id { get; set; }
[Required]
public string Title { get; set; }
}

此外,由于 TPC 是每个(具体)类的表,因此最好将您从abstract继承的类。


我总是以这种方式使用TPC模式。 首先,我将"实体"标记为抽象。实体配置.cs

public class EntityConfiguration<T> : IEntityTypeConfiguration<T> where T : Entity
{
public virtual void Configure(EntityTypeBuilder<T> builder)
{
builder.HasKey(e => e.Id);
builder.Property(e => e.Title).IsRequired();
}
}

书籍配置.cs

public class BookConfiguration : EntityConfiguration<Book>
{
public override void Configure(EntityTypeBuilder<Book> builder)
{
base.Configure(builder);
builder.ToTable("book");
builder.Property(b => b.Edition).HasColumnName("edition");
}
}

使用这种方法,EF 核心将仅创建"book"表,而不使用任何鉴别器。

最新更新