모델 만들기 및 구성

EF Core는 메타데이터 모델을 사용하여 애플리케이션의 엔터티 형식이 기본 데이터베이스에 매핑되는 방법을 설명합니다. 이 모델은 일반적인 패턴을 찾는 추론이라는 규칙 집합을 사용하여 빌드됩니다. 그런 다음 OnModelCreating에서 매핑 특성(데이터 주석이라고도 함)및/또는 ModelBuilder 메서드 (흐름 API라고도 함) 호출을 사용하여 모델을 사용자 지정할 수 있으며, 둘 다 규칙에 의해 수행되는 구성을 재정의합니다.

대부분의 구성은 데이터 저장소를 대상으로 하는 모델에 적용할 수 있습니다. 또한 공급자는 특정 데이터 저장소와 관련된 구성을 사용하도록 설정할 수 있으며 지원되지 않거나 적용되지 않는 구성을 무시할 수도 있습니다. 공급자 특정 구성에 대한 문서는 데이터베이스 공급자 섹션을 참조하세요.

GitHub에서 이 문서의 샘플을 볼 수 있습니다.

Fluent API를 사용하여 모델 구성

파생된 컨텍스트에서 OnModelCreating메서드를 재정의하고 흐름 API를 사용하여 모델을 구성할 수 있습니다. 이것은 가장 강력한 구성 방법으로, 엔터티 클래스를 수정하지 않고도 구성을 지정할 수 있습니다. Fluent API 구성은 우선 순위가 가장 높으며 규칙과 데이터 주석을 재정의합니다. 구성은 메서드가 호출되는 순서대로 적용되며 충돌이 있는 경우 최신 호출이 이전에 지정한 구성을 재정의합니다.

using Microsoft.EntityFrameworkCore;

namespace EFModeling.EntityProperties.FluentAPI.Required;

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

    #region Required
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>()
            .Property(b => b.Url)
            .IsRequired();
    }
    #endregion
}

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

모델의 다중 개체에 동일한 구성을 적용하려면 대량 구성을 참조하세요.

그룹화 구성

OnModelCreating 메서드의 크기를 줄이기 위해 엔터티 형식에 대한 모든 구성을 IEntityTypeConfiguration<TEntity>을 구현하는 별도의 클래스로 추출할 수 있습니다.

public class BlogEntityTypeConfiguration : IEntityTypeConfiguration<Blog>
{
    public void Configure(EntityTypeBuilder<Blog> builder)
    {
        builder
            .Property(b => b.Url)
            .IsRequired();
    }
}

그런 다음, OnModelCreating에서 Configure 메서드를 호출하기만 하면 됩니다.

new BlogEntityTypeConfiguration().Configure(modelBuilder.Entity<Blog>());

어셈블리의 모든 구성 적용

지정된 어셈블리에서 IEntityTypeConfiguration을 구현하는 형식에 지정된 모든 구성을 적용할 수 있습니다.

modelBuilder.ApplyConfigurationsFromAssembly(typeof(BlogEntityTypeConfiguration).Assembly);

참고

구성이 적용되는 순서는 정의되지 않으므로 순서가 중요하지 않은 경우에만 이 메서드를 사용해야 합니다.

엔터티 형식에 EntityTypeConfigurationAttribute 사용

Configure을 명시적으로 호출하는 대신 EF Core에서 적절한 구성을 찾아 사용할 수 있도록 엔터티 형식에 EntityTypeConfigurationAttribute을 배치할 수 있습니다. 예시:

[EntityTypeConfiguration(typeof(BookConfiguration))]
public class Book
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Isbn { get; set; }
}

이 특성은 Book 엔터티 형식이 모델에 포함될 때마다 EF Core에서 지정된 IEntityTypeConfiguration 구현을 사용함을 의미합니다. 엔터티 형식은 일반적인 메커니즘 중 하나를 사용하여 모델에 포함됩니다. 예를 들어 엔터티 형식에 대한 DbSet<TEntity> 속성을 만들어 포함됩니다.

public class BooksContext : DbContext
{
    public DbSet<Book> Books { get; set; }

    //...

또는 OnModelCreating에 등록하여 포함됩니다.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Book>();
}

참고 항목

EntityTypeConfigurationAttribute 형식은 어셈블리에서 자동으로 검색되지 않습니다. 엔터티 형식을 모델에 추가해야 해당 엔터티 형식에서 특성이 검색됩니다.

데이터 주석을 사용하여 모델 구성

일정 특성(데이터 주석이라고 함)을 클래스 및 속성에 적용할 수도 있습니다. 데이터 주석은 규칙을 재정의하지만 흐름 API 구성이 데이터 주석을 재정의합니다.

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;

namespace EFModeling.EntityProperties.DataAnnotations.Annotations;

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

[Table("Blogs")]
public class Blog
{
    public int BlogId { get; set; }

    [Required]
    public string Url { get; set; }
}

기본 제공 규칙

EF Core에는 기본적으로 활성화되는 많은 모델 빌드 규칙이 포함되어 있습니다. IConvention인터페이스를 구현하는 클래스 목록에서 모두 찾을 수 있습니다. 그러나 이 목록에는 타사 데이터베이스 공급자 및 플러그 인에 의해 도입된 규칙이 포함되지 않습니다.

애플리케이션은 이러한 규칙을 제거하거나 대체할 수 있으며, 즉시 사용할 수 있는 EF에서 인식할 수 없는 패턴에 대한 구성을 적용하는 새 사용자 지정 규칙을 추가할 수 있습니다.

아래에 표시된 코드는 ModelBuildingConventionsSample.cs에서 제공됩니다.

기존 규칙 제거

경우에 따라 기본 제공 규칙 중 하나가 애플리케이션에 적합하지 않을 수 있으며, 이 경우 제거할 수 있습니다.

모델이 구성에 매핑 특성(일명 데이터 주석)을 사용하지 않는 경우 이름이 AttributeConvention으로 끝나는 모든 규칙을 안전하게 제거하여 모델 빌드 속도를 높일 수 있습니다.

예: 외래 키 열에 대한 인덱스를 만들지 마세요.

일반적으로 FK(외래 키) 열에 대한 인덱스를 만드는 것이 합리적이므로 다음의 ForeignKeyIndexConvention과 같은 기본 제공 규칙이 있습니다. BlogAuthor에 대한 관계가 있는 Post 엔터티 형식에 대한 모델 디버그 보기를 보면 두 개의 인덱스가 만들어진 것을 볼 수 있습니다. 하나는 BlogId FK용이고 다른 하나는 AuthorId FK용입니다.

  EntityType: Post
    Properties:
      Id (int) Required PK AfterSave:Throw ValueGenerated.OnAdd
      AuthorId (no field, int?) Shadow FK Index
      BlogId (no field, int) Shadow Required FK Index
    Navigations:
      Author (Author) ToPrincipal Author Inverse: Posts
      Blog (Blog) ToPrincipal Blog Inverse: Posts
    Keys:
      Id PK
    Foreign keys:
      Post {'AuthorId'} -> Author {'Id'} ToDependent: Posts ToPrincipal: Author ClientSetNull
      Post {'BlogId'} -> Blog {'Id'} ToDependent: Posts ToPrincipal: Blog Cascade
    Indexes:
      AuthorId
      BlogId

그러나 인덱스에는 오버헤드가 있으며 모든 FK 열에 대해 인덱스를 만드는 것이 항상 적절하지는 않을 수 있습니다. 이를 위해 ForeignKeyIndexConvention은 모델을 빌드할 때 제거할 수 있습니다.

protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
    configurationBuilder.Conventions.Remove(typeof(ForeignKeyIndexConvention));
}

Post 현재 모델의 디버그 보기를 살펴보면 FK의 인덱스가 만들어지지 않은 것을 볼 수 있습니다.

  EntityType: Post
    Properties:
      Id (int) Required PK AfterSave:Throw ValueGenerated.OnAdd
      AuthorId (no field, int?) Shadow FK
      BlogId (no field, int) Shadow Required FK
    Navigations:
      Author (Author) ToPrincipal Author Inverse: Posts
      Blog (Blog) ToPrincipal Blog Inverse: Posts
    Keys:
      Id PK
    Foreign keys:
      Post {'AuthorId'} -> Author {'Id'} ToDependent: Posts ToPrincipal: Author ClientSetNull
      Post {'BlogId'} -> Blog {'Id'} ToDependent: Posts ToPrincipal: Blog Cascade

원하는 경우 인덱스는 IndexAttribute를 사용하거나 OnModelCreating의 구성을 사용하여 외래 키 열에 대해 명시적으로 만들어질 수 있습니다.

디버그 보기

모델 작성기 디버그 보기는 IDE의 디버거에서 액세스할 수 있습니다. 예를 들어 Visual Studio를 사용하면 다음과 같습니다.

Accessing the model builder debug view from the Visual Studio debugger

코드에서 직접 액세스할 수도 있습니다. 예를 들어 디버그 보기를 콘솔로 보냅니다.

Console.WriteLine(context.Model.ToDebugString());

디버그 보기에는 짧은 양식과 긴 양식이 있습니다. 긴 양식에는 관계형 또는 공급자별 메타데이터를 확인해야 하는 경우에 유용할 수 있는 모든 주석도 포함됩니다. 긴 보기는 코드에서도 액세스할 수 있습니다.

Console.WriteLine(context.Model.ToDebugString(MetadataDebugStringOptions.LongDefault));