다음을 통해 공유


관련 엔터티 로드

Entity Framework는 관련 데이터를 로드하는 세 가지 방법인 즉시 로드, 지연 로드, 명시적 로드를 지원합니다. 이 토픽에서 설명하는 방법은 Code First 및 EF 디자이너를 사용하여 만든 모델에 동일하게 적용됩니다.

즉시 로드

즉시 로드는 하나의 엔터티 형식에 대한 쿼리가 관련 엔터티도 쿼리의 일부로 로드하는 프로세스입니다. 즉시 로드는 Include 메서드를 사용하여 구현됩니다. 예를 들어 아래 쿼리는 블로그 및 각 블로그와 관련된 모든 게시물을 로드합니다.

using (var context = new BloggingContext())
{
    // Load all blogs and related posts.
    var blogs1 = context.Blogs
                        .Include(b => b.Posts)
                        .ToList();

    // Load one blog and its related posts.
    var blog1 = context.Blogs
                       .Where(b => b.Name == "ADO.NET Blog")
                       .Include(b => b.Posts)
                       .FirstOrDefault();

    // Load all blogs and related posts
    // using a string to specify the relationship.
    var blogs2 = context.Blogs
                        .Include("Posts")
                        .ToList();

    // Load one blog and its related posts
    // using a string to specify the relationship.
    var blog2 = context.Blogs
                       .Where(b => b.Name == "ADO.NET Blog")
                       .Include("Posts")
                       .FirstOrDefault();
}

참고 항목

Include는 System.Data.Entity 네임스페이스의 확장 메서드이므로 해당 네임스페이스를 사용하고 있는지 확인해야 합니다.

여러 수준을 즉시 로드

여러 수준의 관련 엔터티를 즉시 로드할 수도 있습니다. 아래 쿼리는 컬렉션 및 참조 탐색 속성 모두에 대해 이 작업을 수행하는 방법의 예제를 보여 줍니다.

using (var context = new BloggingContext())
{
    // Load all blogs, all related posts, and all related comments.
    var blogs1 = context.Blogs
                        .Include(b => b.Posts.Select(p => p.Comments))
                        .ToList();

    // Load all users, their related profiles, and related avatar.
    var users1 = context.Users
                        .Include(u => u.Profile.Avatar)
                        .ToList();

    // Load all blogs, all related posts, and all related comments  
    // using a string to specify the relationships.
    var blogs2 = context.Blogs
                        .Include("Posts.Comments")
                        .ToList();

    // Load all users, their related profiles, and related avatar  
    // using a string to specify the relationships.
    var users2 = context.Users
                        .Include("Profile.Avatar")
                        .ToList();
}

참고 항목

현재 로드되는 관련 엔터티는 필터링할 수 없습니다. Include는 항상 모든 관련 엔터티를 가져옵니다.

지연 로드

지연 로드는 엔터티를 참조하는 속성에 처음 액세스할 때 엔터티 또는 엔터티 컬렉션이 데이터베이스에서 자동으로 로드되는 프로세스입니다. POCO 엔터티 형식을 사용할 경우 파생된 프록시 형식의 인스턴스를 만든 다음 가상 속성을 재정의하여 로딩 후크를 추가하는 방식으로 지연 로드가 이루어집니다. 예를 들어 아래에 정의된 Blog 엔터티 클래스를 사용하는 경우 Posts 탐색 속성에 처음 액세스할 때 관련 게시물이 로드됩니다.

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

    public virtual ICollection<Post> Posts { get; set; }
}

serialization을 위해 지연 로드 끄기

지연 로드 및 serialization은 함께 사용하기에 적합하지 않으며, 주의하지 않으면 지연 로드가 활성화되어 있다는 이유만으로 전체 데이터베이스에 대해 쿼리할 수 있습니다. 대부분의 직렬 변환기는 형식 인스턴스의 각 속성에 액세스하여 작동합니다. 속성 액세스는 지연 로드를 트리거하므로 더 많은 엔터티가 직렬화됩니다. 해당 엔터티 속성에 액세스하고 훨씬 더 많은 엔터티가 로드됩니다. 엔터티를 직렬화하기 전에 지연 로드를 끄는 것이 좋습니다. 다음 섹션에서는 이 작업을 수행하는 방법을 보여 줍니다.

특정 탐색 속성에 대한 지연 로드 끄기

Posts 속성을 가상이 아닌 상태로 만들어 Posts 컬렉션의 지연 로드를 끌 수 있습니다.

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

    public ICollection<Post> Posts { get; set; }
}

Posts 컬렉션은 즉시 로드(위의 즉시 로드 참조) 또는 Load 메서드(아래의 명시적 로드 참조)를 사용하여 계속 로드할 수 있습니다.

모든 엔터티에 대해 지연 로드 끄기

Configuration 속성에 플래그를 설정하여 컨텍스트의 모든 엔터티에 대해 지연 로드를 끌 수 있습니다. 예시:

public class BloggingContext : DbContext
{
    public BloggingContext()
    {
        this.Configuration.LazyLoadingEnabled = false;
    }
}

관련 엔터티는 즉시 로드(위의 즉시 로드 참조) 또는 Load 메서드(아래의 명시적 로드 참조)를 사용하여 계속 로드할 수 있습니다.

명시적 로드

지연 로드를 사용할 수 없어도 관련 엔터티를 지연 로드할 수 있지만 명시적 호출을 통해 수행해야 합니다. 이렇게 하려면 관련 엔터티의 항목에서 Load 메서드를 사용합니다. 예시:

using (var context = new BloggingContext())
{
    var post = context.Posts.Find(2);

    // Load the blog related to a given post.
    context.Entry(post).Reference(p => p.Blog).Load();

    // Load the blog related to a given post using a string.
    context.Entry(post).Reference("Blog").Load();

    var blog = context.Blogs.Find(1);

    // Load the posts related to a given blog.
    context.Entry(blog).Collection(p => p.Posts).Load();

    // Load the posts related to a given blog
    // using a string to specify the relationship.
    context.Entry(blog).Collection("Posts").Load();
}

참고 항목

엔터티에 다른 단일 엔터티에 대한 탐색 속성이 있는 경우 Reference 메서드를 사용해야 합니다. 반면에 엔터티에 다른 엔터티 컬렉션에 대한 탐색 속성이 있는 경우 Collection 메서드를 사용해야 합니다.

Query 메서드는 Entity Framework가 관련 엔터티를 로드할 때 사용할 기본 쿼리에 대한 액세스를 허용합니다. 그런 다음 LINQ를 사용하여 쿼리에 필터를 적용한 후 ToList, Load 등의 LINQ 확장 메서드를 호출하여 실행할 수 있습니다. Query 메서드는 참조 및 컬렉션 탐색 속성을 모두 함께 사용할 수 있지만 컬렉션 일부만 로드하는 데 사용할 수 있는 컬렉션에 가장 유용합니다. 예시:

using (var context = new BloggingContext())
{
    var blog = context.Blogs.Find(1);

    // Load the posts with the 'entity-framework' tag related to a given blog.
    context.Entry(blog)
           .Collection(b => b.Posts)
           .Query()
           .Where(p => p.Tags.Contains("entity-framework"))
           .Load();

    // Load the posts with the 'entity-framework' tag related to a given blog
    // using a string to specify the relationship.
    context.Entry(blog)
           .Collection("Posts")
           .Query()
           .Where(p => p.Tags.Contains("entity-framework"))
           .Load();
}

Query 메서드를 사용하는 경우 일반적으로 탐색 속성에 대한 지연 로드를 끄는 것이 가장 좋습니다. 그렇지 않으면 필터링된 쿼리가 실행되기 전후에 지연 로드 메커니즘을 통해 전체 컬렉션이 자동으로 로드될 수 있기 때문입니다.

참고 항목

관계를 람다 식 대신 문자열로 지정할 수 있지만 문자열을 사용할 경우 반환된 IQueryable은 일반적이지 않으며, 유용한 작업을 수행하기 전에는 일반적으로 Cast 메서드가 필요합니다.

실제로 모든 엔터티를 로드하는 비용을 발생시키지 않고 데이터베이스의 다른 엔터티와 관련된 엔터티 수를 파악하는 것이 유용한 경우도 있습니다. 이 작업을 수행하려면 LINQ Count 메서드와 함께 Query 메서드를 사용하세요. 예시:

using (var context = new BloggingContext())
{
    var blog = context.Blogs.Find(1);

    // Count how many posts the blog has.
    var postCount = context.Entry(blog)
                           .Collection(b => b.Posts)
                           .Query()
                           .Count();
}