다음을 통해 공유


키 없는 엔터티 형식

비고

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

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

키 없는 엔터티 형식 정의

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

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

키 없는 엔터티 형식 특성

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

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

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

사용 시나리오

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

  • SQL 쿼리의 반환 형식으로 사용
  • 기본 키가 포함되지 않은 데이터베이스 뷰에 매핑합니다.
  • 기본 키가 정의되지 않은 테이블에 매핑합니다.
  • 모델에 정의된 쿼리에 매핑합니다.

데이터베이스 개체에 매핑

키 없는 엔터티 형식을 데이터베이스 개체에 매핑하는 작업은 ToTable 또는 ToView Fluent 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; }
}

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

await db.Database.ExecuteSqlRawAsync(
    @"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; }
}

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

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

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

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

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

var postCounts = await db.BlogPostCounts.ToListAsync();

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

팁 (조언)

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

팁 (조언)

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