Sdílet prostřednictvím


Opožděné načítání souvisejících dat

Opožděné načítání s proxy servery

Nejjednodušší způsob, jak používat opožděné načítání, spočívá v instalaci balíčku Microsoft.EntityFrameworkCore.Proxies a povolením volání UseLazyLoadingProxies. Příklad:

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

Nebo při použití addDbContext:

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

EF Core pak povolí opožděné načítání pro všechny navigační vlastnosti, které lze přepsat- to znamená, že musí být virtual a ve třídě, ze které lze dědit. Například v následujících entitách Post.Blog budou vlastnosti a Blog.Posts navigace opožděně načteny.

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

Upozorňující

Opožděné načítání může způsobit výskyt nepotřebných dodatečných cyklů databáze (tzv. problém N+1) a měli byste se tomu vyhnout. Další podrobnosti najdete v části o výkonu.

Opožděné načítání bez proxy serverů

Opožděné načítání bez proxy fungují vložením ILazyLoader služby do entity, jak je popsáno v konstruktorech typů entit. Příklad:

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

Tato metoda nevyžaduje, aby typy entit byly zděděny z vlastností navigace nebo aby byly virtuální, a umožňuje instancím entit vytvořeným new s opožděným načtením po připojení k kontextu. Vyžaduje však odkaz na ILazyLoader službu, která je definována v balíčku Microsoft.EntityFrameworkCore.Abstractions . Tento balíček obsahuje minimální sadu typů, aby v závislosti na něm byl malý dopad. Pokud se ale chcete zcela vyhnout v závislosti na jakýchkoli balíčcích EF Core v typech entit, je možné metodu ILazyLoader.Load vložit jako delegáta. Příklad:

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

Výše uvedený kód používá metodu Load rozšíření, která delegáta trochu čistí:

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

Poznámka

Parametr konstruktoru pro opožděný delegát načítání musí být volána "lazyLoader". Konfigurace pro použití jiného názvu, než je naplánováno pro budoucí verzi.