관련 데이터의 지연 로드

프록시를 사용한 지연 로드

지연 로드를 사용하는 가장 간단한 방법은 Microsoft.EntityFrameworkCore.Proxies 패키지를 설치하고 이를 사용하여 UseLazyLoadingProxies를 호출하는 것입니다. 예를 들어:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder
        .UseLazyLoadingProxies()
        .UseSqlServer(myConnectionString);

또는 AddDbContext를 사용하는 경우:

.AddDbContext<BloggingContext>(
    b => b.UseLazyLoadingProxies()
          .UseSqlServer(myConnectionString));

EF Core에서 재정의할 수 있는 모든 탐색 속성에 대해 지연 로드를 사용합니다. 즉, virtual이어야 하고 상속될 수 있는 클래스에 있어야 합니다. 예를 들어 다음 엔터티에서 Post.BlogBlog.Posts 탐색 속성은 지연 로드됩니다.

public class Blog
{
    public int Id { get; set; }
    public string Name { get; set; }

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

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

    public virtual Blog Blog { get; set; }
}

경고

지연 로드로 인해 불필요한 추가 데이터베이스 왕복이 발생할 수 있으므로(N+1 문제라고 함) 이 문제를 방지하기 위해 주의를 기울여야 합니다. 자세한 내용은 성능 섹션을 참조하세요.

프록시 없는 지연 로드

프록시 없는 지연 로드는 엔터티 형식 생성자에 설명된 대로 ILazyLoader 서비스를 엔터티에 삽입하여 작동합니다. 예를 들어:

public class Blog
{
    private ICollection<Post> _posts;

    public Blog()
    {
    }

    private Blog(ILazyLoader lazyLoader)
    {
        LazyLoader = lazyLoader;
    }

    private ILazyLoader LazyLoader { get; set; }

    public int Id { get; set; }
    public string Name { get; set; }

    public ICollection<Post> Posts
    {
        get => LazyLoader.Load(this, ref _posts);
        set => _posts = value;
    }
}

public class Post
{
    private Blog _blog;

    public Post()
    {
    }

    private Post(ILazyLoader lazyLoader)
    {
        LazyLoader = lazyLoader;
    }

    private ILazyLoader LazyLoader { get; set; }

    public int Id { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public Blog Blog
    {
        get => LazyLoader.Load(this, ref _blog);
        set => _blog = value;
    }
}

이 방법에서는 상속되는 엔터티 형식이나 탐색 속성이 가상일 필요가 없으며, 컨텍스트에 연결되면 new로 만든 엔터티 인스턴스가 지연 로드됩니다. 하지만 Microsoft.EntityFrameworkCore.Abstractions 패키지에 정의된 ILazyLoader 서비스에 대한 참조가 필요합니다. 이 패키지에는 최소의 형식 세트가 포함되어 있으므로 이 패키지에 따른 영향이 거의 없습니다. 그러나 엔터티 형식의 EF Core 패키지를 전혀 사용하지 않으려면 ILazyLoader.Load 메서드를 대리자로 삽입할 수 있습니다. 예를 들어:

public class Blog
{
    private ICollection<Post> _posts;

    public Blog()
    {
    }

    private Blog(Action<object, string> lazyLoader)
    {
        LazyLoader = lazyLoader;
    }

    private Action<object, string> LazyLoader { get; set; }

    public int Id { get; set; }
    public string Name { get; set; }

    public ICollection<Post> Posts
    {
        get => LazyLoader.Load(this, ref _posts);
        set => _posts = value;
    }
}

public class Post
{
    private Blog _blog;

    public Post()
    {
    }

    private Post(Action<object, string> lazyLoader)
    {
        LazyLoader = lazyLoader;
    }

    private Action<object, string> LazyLoader { get; set; }

    public int Id { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public Blog Blog
    {
        get => LazyLoader.Load(this, ref _blog);
        set => _blog = value;
    }
}

위의 코드에서는 Load 확장 메서드를 사용하여 대리자 사용을 좀 더 깔끔하게 합니다.

public static class PocoLoadingExtensions
{
    public static TRelated Load<TRelated>(
        this Action<object, string> loader,
        object entity,
        ref TRelated navigationField,
        [CallerMemberName] string navigationName = null)
        where TRelated : class
    {
        loader?.Invoke(entity, navigationName);

        return navigationField;
    }
}

참고

지연 로드 대리자에 대한 생성자 매개 변수를 “lazyLoader”라고 합니다. 이와 다른 이름을 사용하는 구성은 향후 릴리스에 포함될 예정입니다.