EF Core Fluent API配置如何防止TPC继承

4

我有几个继承关系的模型,但我很难让流畅的 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; }
}

最后,我添加迁移 Initial。

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

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

我为实体添加了一个配置。

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

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

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

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

当我执行"add-migration"命令时,会得到以下结果。
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 OnModelCreating方法中直接配置Entity,而不是使用单独的配置类,但结果与之前相同。
EF Core文档实际上说不支持TPC,这很奇怪,因为它确实为子类创建了单独的表格,直到我尝试配置基类为止。
我已经尝试使用Ignore()来抑制TPH,但这没有效果。
给出的示例并非真实世界。我的实际项目有更多的类,它们都有共同的属性和关系,所以我想避免一遍又一遍地配置相同的内容。

嗨@Toby,这个行了吗? - Steve Padmore
嗨@StevePadmore,感谢您的回答。不幸的是,我需要避免在我的模型类中使用任何类型的注释,因此这条路不可行。实际上,我找到了一种方法来实现我想要的功能,通过编写自己的映射类而不是使用内置配置。我将写下我所做的事情,并添加一个答案,以防其他人有同样的问题。谢谢 :) - Toby
2
嗨Toby,你介意分享一下你是如何解决你最初的问题的吗? - eja
2个回答

4

您说的没错,截至目前为止,EF Core不支持TPC。

但是,似乎有一种方法可以绕过此问题(至少适用于生成“Up”脚本)。

删除FluentAPI注册,并在实体类属性上使用Annotations

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

此外,因为TPC是每个(具体)类为一张表的模式,所以最好将您要继承的类声明为抽象类。

1

EntityConfiguration.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();
        }
    }

BookConfiguration.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 Core 只会创建“book”表,而不使用任何鉴别器。


但这不是TPC。TPC允许在一个语句中查询所有派生类型,EF会自动生成连接。 - Gert Arnold
@GertArnold 谢谢您的解释。无论如何,我认为作者的目的是定义一个基类,并且只需指定其配置一次,派生类应该选择此配置。 - ossan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接