继承

EF 可以将 .NET 类型层次结构映射到数据库。 这使你可以像平常一样使用基类型和派生类型在代码中编写 .NET 实体,并让 EF 无缝创建适当的数据库架构、发出查询等。
目前,EF Core 仅支持每个层次结构一个表(TPH)模式。 TPH 使用单个表来存储层次结构中所有类型的数据,而鉴别器列用于标识每行所表示的类型。

实体类型层次结构映射

按照约定,EF 不会自动扫描基类型或派生类型;这意味着,如果要映射层次结构中的 CLR 类型,则必须在模型上显式指定该类型。 例如,仅指定层次结构的基类型将不会导致 EF Core 隐式包含其所有子类型。
下面的示例为及其子类公开了 DbSet Blog RssBlog 。 如果 Blog 有任何其他子类,则不会将其包含在模型中。
class MyContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<RssBlog> RssBlogs { get; set; }
}

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }
}

public class RssBlog : Blog
{
    public string RssUrl { get; set; }
}

此模型映射到下面的数据库架构(请注意隐式创建的鉴别器列,该列标识每个行中存储的博客类型):

BlogId Discriminator Url RssUrl
1 Blog https://docs.microsoft.com NULL
2 RssBlog https://docs.microsoft.com https://docs.microsoft.com
CREATE TABLE Blogs (BlogId INT PRIMARY KEY NOT NULL,Discriminator VARCHAR(64) NOT NULL,Url VARCHAR(128) NOT NULL,RssUrl VARCHAR(128));

鉴别器配置

您可以配置鉴别器列的名称(默认Discriminator)和类型以及用于标识层次结构中的每种类型的值:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasDiscriminator<string>("blog_type")
        .HasValue<Blog>("blog_base")
        .HasValue<RssBlog>("blog_rss");
}

在上述示例中,EF 在层次结构的基实体上将鉴别器隐式添加为阴影属性。 此属性可以配置为类似于任何其他属性:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .Property("Discriminator")
        .HasMaxLength(128);
}

最后,鉴别器还可以映射到实体中的常规 .NET 属性:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasDiscriminator(b => b.BlogType);

    modelBuilder.Entity<Blog>()
        .Property(e => e.BlogType)
        .HasMaxLength(200)
        .HasColumnName("blog_type");
}

共享列

默认情况下,当层次结构中的两个兄弟实体类型具有相同名称的属性时,它们将映射到两个单独的列。 但是,如果它们的类型相同,它们可以映射到同一个数据库列:

public class MyContext : DbContext
{
    public DbSet<BlogBase> Blogs { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>()
            .Property(b => b.Url)
            .HasColumnName("Url");

        modelBuilder.Entity<RssBlog>()
            .Property(b => b.Url)
            .HasColumnName("Url");
    }
}

public abstract class BlogBase
{
    public int BlogId { get; set; }
}

public class Blog : BlogBase
{
    public string Url { get; set; }
}

public class RssBlog : BlogBase
{
    public string Url { get; set; }
}