키 없는 엔터티 형식

참고 항목

이 기능은 쿼리 형식의 이름 아래에 추가되었습니다. 나중에 키가 없는 엔터티 형식으로 이름이 바뀌었습니다.

일반 엔터티 형식 외에도 EF Core 모델에는 키 없는 엔터티 형식이 포함될 수 있으며, 키 값이 포함되지 않은 데이터에 대해 데이터베이스 쿼리를 수행하는 데 사용할 수 있습니다.

키 없는 엔터티 형식

키 없는 엔터티 형식은 다음과 같이 정의할 수 있습니다.

[Keyless]
public class BlogPostsCount
{
    public string BlogName { get; set; }
    public int PostCount { get; set; }
}

키 없는 엔터티 형식

키 없는 엔터티 형식은 상속 매핑 및 탐색 속성과 같은 일반 엔터티 형식과 동일한 많은 매핑 기능을 지원합니다. 관계형 저장소에서 흐름 API 메서드 또는 데이터 주석을 통해 대상 데이터베이스 개체 및 열을 구성할 수 있습니다.

그러나 다음과 같은 측면에서 일반 엔터티 형식과 다릅니다.

  • 키를 정의할 수 없습니다.
  • DbContext의 변경 내용을 추적하지 않으므로 데이터베이스에 삽입, 업데이트 또는 삭제되지 않습니다.
  • 규칙에 의해 검색되지 않습니다.
  • 탐색 매핑 기능의 하위 집합, 특히 다음만 지원합니다.
    • 그들은 관계의 주체 끝 역할을 하지 않을 수 있습니다.
    • 소유 엔터티에 대한 탐색이 없을 수 있습니다.
    • 일반 엔터티를 가리키는 참조 탐색 속성만 포함할 수 있습니다.
    • 엔터티는 키 없는 엔터티 형식에 대한 탐색 속성을 포함할 수 없습니다.
  • [Keyless] 데이터 주석 또는 .HasNoKey() 메서드 호출을 사용하여 구성해야 합니다.
  • 정의 쿼리에 매핑될 수 있습니다. 정의 쿼리는 키 없는 엔터티 형식의 데이터 원본 역할을 하는 모델에서 선언된 쿼리입니다.
  • 계층 구조를 가질 수 있지만 TPH로 매핑되어야 합니다.
  • 테이블 분할 또는 엔터티 분할을 사용할 수 없습니다.

사용 시나리오

키 없는 엔터티 형식에 대한 몇 가지 주요 사용 시나리오는 다음과 같습니다.

  • SQL 쿼리에 대한 반환 형식으로 제공.
  • 기본 키가 포함되지 않은 데이터베이스 뷰에 매핑.
  • 기본 키가 정의되지 않은 테이블에 매핑.
  • 모델에서 정의된 쿼리에 매핑.

데이터베이스 개체에 매핑

ToTable 또는 ToView 흐름 API를 사용하여 키 없는 엔터티 형식을 데이터베이스 개체에 매핑. EF Core의 관점에서 이 메서드에 지정된 데이터베이스 개체는 입니다. 즉, 읽기 전용 쿼리 원본으로 처리되며 업데이트, 삽입 또는 삭제 작업의 대상이 될 수 없습니다. 그러나 데이터베이스 개체가 실제로 데이터베이스 뷰여야 한다는 의미는 아닙니다. 또는 읽기 전용으로 처리되는 데이터베이스 테이블일 수 있습니다. 반대로, 일반 엔터티 형식의 경우 EF Core는 ToTable 메서드에 지정된 데이터베이스 개체를 테이블로 처리할 수 있다고 가정합니다. 즉, 쿼리 원본으로 사용할 수 있지만 업데이트, 삭제 및 삽입 작업의 대상이 될 수도 있습니다. 실제로 ToTable에서 데이터베이스 뷰의 이름을 지정할 수 있으며 데이터베이스에서 뷰를 업데이트할 수 있도록 구성된 경우 모든 항목이 제대로 작동해야 합니다.

예시

다음 예제에서는 키 없는 엔터티 형식을 사용하여 데이터베이스 뷰를 쿼리하는 방법을 보여줍니다.

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

먼저 간단한 블로그 및 게시 모델을 정의합니다.

public class Blog
{
    public int BlogId { get; set; }
    public string Name { get; set; }
    public string Url { get; set; }
    public ICollection<Post> Posts { get; set; }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    public int BlogId { get; set; }
}

다음으로, 각 블로그와 연결된 게시물 수를 쿼리할 수 있는 간단한 데이터베이스 보기를 정의합니다.

db.Database.ExecuteSqlRaw(
    @"CREATE VIEW View_BlogPostCounts AS
                SELECT b.Name, Count(p.PostId) as PostCount
                FROM Blogs b
                JOIN Posts p on p.BlogId = b.BlogId
                GROUP BY b.Name");

다음으로 데이터베이스 뷰의 결과를 저장할 클래스를 정의합니다.

public class BlogPostsCount
{
    public string BlogName { get; set; }
    public int PostCount { get; set; }
}

다음으로, HasNoKey API를 사용하여 OnModelCreating에서 키 없는 엔터티 형식을 구성합니다. 흐름 구성 API를 사용하여 키 없는 엔터티 형식에 대한 매핑을 구성합니다.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder
        .Entity<BlogPostsCount>(
            eb =>
            {
                eb.HasNoKey();
                eb.ToView("View_BlogPostCounts");
                eb.Property(v => v.BlogName).HasColumnName("Name");
            });
}

다음으로, DbSet<T>를 포함하도록 DbContext를 구성합니다.

public DbSet<BlogPostsCount> BlogPostCounts { get; set; }

마지막으로, 표준 방식으로 데이터베이스 뷰를 쿼리할 수 있습니다.

var postCounts = db.BlogPostCounts.ToList();

foreach (var postCount in postCounts)
{
    Console.WriteLine($"{postCount.BlogName} has {postCount.PostCount} posts.");
    Console.WriteLine();
}

또한 이 형식에 대한 쿼리의 루트 역할을 하는 컨텍스트 수준 쿼리 속성(DbSet)도 정의했습니다.

메모리 내 공급자를 사용하여 뷰에 매핑된 키 없는 엔터티 형식을 테스트하려면 ToInMemoryQuery를 통해 쿼리에 매핑합니다. 자세한 내용은 메모리 내 공급자 문서를 참조하세요.