Udostępnij za pośrednictwem


Leniwe ładowanie powiązanych danych

Ładowanie z opóźnieniem za pomocą serwerów proxy

Najprostszym sposobem korzystania z ładowania leniwego jest zainstalowanie pakietu Microsoft.EntityFrameworkCore.Proxies i włączenie go za pomocą wywołania metody UseLazyLoadingProxies. Przykład:

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

Lub w przypadku korzystania z polecenia AddDbContext:

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

Następnie program EF Core włączy ładowanie opóźnione dla dowolnej właściwości nawigacji, która może zostać zastąpiona — musi to być virtual i w klasie, z którą można dziedziczyć. Na przykład w następujących jednostkach Post.Blog właściwości nawigacji i Blog.Posts zostaną załadowane z opóźnieniem.

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; }
}

Ostrzeżenie

Ładowanie leniwe może spowodować, że wystąpią niepotrzebne dodatkowe przejazdy bazy danych (tak zwany problem N+1) i należy zadbać o to, aby tego uniknąć. Aby uzyskać więcej informacji, zobacz sekcję wydajności.

Ładowanie z opóźnieniem bez serwerów proxy

Ładowanie z opóźnieniem bez serwerów proxy działa przez wstrzyknięcie ILazyLoader usługi do jednostki, zgodnie z opisem w temacie Entity Type Constructors (Konstruktory typów jednostek). Przykład:

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;
    }
}

Ta metoda nie wymaga dziedziczenia typów jednostek z właściwości nawigacji lub jest wirtualna i umożliwia tworzenie wystąpień jednostek z new opóźnieniem ładowania po dołączeniu do kontekstu. Wymaga jednak odwołania do ILazyLoader usługi zdefiniowanej w pakiecie Microsoft.EntityFrameworkCore.Abstractions . Ten pakiet zawiera minimalny zestaw typów, dzięki czemu w zależności od niego ma niewielki wpływ. Jednak aby całkowicie uniknąć w zależności od pakietów EF Core w typach jednostek, można wstrzyknąć metodę ILazyLoader.Load jako delegata. Przykład:

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;
    }
}

Powyższy kod używa Load metody rozszerzenia, aby używać delegata do czyszczenia bitów:

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;
    }
}

Uwaga

Parametr konstruktora dla delegata ładowania leniwego musi być nazywany "lazyLoader". Konfiguracja używania innej nazwy niż ta jest planowana dla przyszłej wersji.