상속Inheritance

EF는 .NET 형식 계층 구조를 데이터베이스에 매핑할 수 있습니다.EF can map a .NET type hierarchy to a database. 이를 통해 기본 및 파생 형식을 사용 하 여 일반적인 방식으로 코드에 .NET 엔터티를 작성 하 고 EF에서 적절 한 데이터베이스 스키마를 원활 하 게 만들고 쿼리를 실행할 수 있습니다. 형식 계층 구조를 매핑하는 방법에 대 한 실제 세부 정보는 공급자에 따라 다릅니다. 이 페이지에서는 관계형 데이터베이스의 컨텍스트에서 상속 지원을 설명 합니다.This allows you to write your .NET entities in code as usual, using base and derived types, and have EF seamlessly create the appropriate database schema, issue queries, etc. The actual details of how a type hierarchy is mapped are provider-dependent; this page describes inheritance support in the context of a relational database.

현재 EF Core는 TPH (계층당 하나의 테이블) 패턴만 지원 합니다.At the moment, EF Core only supports the table-per-hierarchy (TPH) pattern. TPH는 단일 테이블을 사용 하 여 계층의 모든 형식에 대 한 데이터를 저장 하 고, 판별자 열은 각 행이 나타내는 유형을 식별 하는 데 사용 됩니다.TPH uses a single table to store the data for all types in the hierarchy, and a discriminator column is used to identify which type each row represents.

참고

EF6에서 지원 되는 형식당 하나의 테이블 (TPT) 및 테이블당 (테이블당) (TPC)는 EF Core에서 아직 지원 되지 않습니다.The table-per-type (TPT) and table-per-concrete-type (TPC), which are supported by EF6, are not yet supported by EF Core. TPT는 EF Core 5.0에 대해 계획 된 주요 기능입니다.TPT is a major feature planned for EF Core 5.0.

엔터티 형식 계층 구조 매핑Entity type hierarchy mapping

규칙에 따라 EF는 기본 또는 파생 형식을 자동으로 검색 하지 않습니다. 즉, 계층 구조에서 CLR 형식을 매핑하도록 하려면 모델에 해당 형식을 명시적으로 지정 해야 합니다.By convention, EF will not automatically scan for base or derived types; this means that if you want a CLR type in your hierarchy to be mapped, you must explicitly specify that type on your model. 예를 들어 계층의 기본 형식만 지정 하면 EF Core는 해당 하위 형식을 암시적으로 포함 하지 않습니다.For example, specifying only the base type of a hierarchy will not cause EF Core to implicitly include all of its sub-types.

다음 샘플에서는 Blog 및 해당 하위 클래스에 대 한 DbSet를 제공 합니다 RssBlog .The following sample exposes a DbSet for Blog and its subclass RssBlog. Blog에 다른 하위 클래스가 있으면 모델에 포함 되지 않습니다.If Blog has any other subclass, it will not be included in the model.

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; }
}

이 모델은 다음 데이터베이스 스키마에 매핑됩니다 (각 행에 저장 되는 블로그의 유형을 식별 하는 암시적으로 만든 판별자 열에 유의).This model is mapped to the following database schema (note the implicitly-created Discriminator column, which identifies which type of Blog is stored in each row):

이미지

참고

TPH 매핑을 사용 하는 경우 필요에 따라 데이터베이스 열이 자동으로 nullable로 설정 됩니다.Database columns are automatically made nullable as necessary when using TPH mapping. 예를 들어 일반 블로그 인스턴스에는 해당 속성이 없으므로 rssurl 열은 null을 허용 합니다.For example, the RssUrl column is nullable because regular Blog instances do not have that property.

계층 구조에 있는 하나 이상의 엔터티에 대해 DbSet을 노출 하지 않으려는 경우 흐름 API를 사용 하 여 모델에 포함 되도록 할 수도 있습니다.If you don't want to expose a DbSet for one or more entities in the hierarchy, you can also use the Fluent API to ensure they are included in the model.

규칙을 사용 하지 않는 경우를 사용 하 여 명시적으로 기본 형식을 지정할 수 있습니다 HasBaseType .If you don't rely on conventions, you can specify the base type explicitly using HasBaseType. 를 사용 하 여 .HasBaseType((Type)null) 계층 구조에서 엔터티 형식을 제거할 수도 있습니다.You can also use .HasBaseType((Type)null) to remove an entity type from the hierarchy.

판별자 구성Discriminator configuration

판별자 열의 이름 및 유형과 계층의 각 유형을 식별 하는 데 사용 되는 값을 구성할 수 있습니다.You can configure the name and type of the discriminator column and the values that are used to identify each type in the hierarchy:

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

위의 예제에서 EF는 계층의 기본 엔터티에서 명시적으로 판별자를 그림자 속성 으로 추가 했습니다.In the examples above, EF added the discriminator implicitly as a shadow property on the base entity of the hierarchy. 이 속성은 다음과 같이 구성할 수 있습니다.This property can be configured like any other:

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

마지막으로, 판별자를 엔터티의 일반 .NET 속성에 매핑할 수도 있습니다.Finally, the discriminator can also be mapped to a regular .NET property in your entity:

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");
}

공유 열Shared columns

기본적으로 계층의 두 형제 엔터티 형식에 동일한 이름의 속성이 있는 경우 두 개의 개별 열에 매핑됩니다.By default, when two sibling entity types in the hierarchy have a property with the same name, they will be mapped to two separate columns. 그러나 형식이 동일한 경우 동일한 데이터베이스 열에 매핑될 수 있습니다.However, if their type is identical they can be mapped to the same database column:

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; }
}