Condividi tramite


Caricamento differita dei dati correlati

Caricamento differita con proxy

Il modo più semplice per usare il caricamento lazy consiste nell'installare il pacchetto Microsoft.EntityFrameworkCore.Proxies e abilitarlo con una chiamata a UseLazyLoadingProxies. Ad esempio:

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

O quando si usa AddDbContext:

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

EF Core abiliterà quindi il caricamento lazy per qualsiasi proprietà di navigazione che può essere sottoposta a override, ovvero deve essere virtual e in una classe ereditabile. Ad esempio, nelle entità seguenti, le proprietà di navigazione Post.Blog e Blog.Posts vengono caricate in modalità lazy.

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

Avviso

Il caricamento differita può causare l'esecuzione di round trip aggiuntivi aggiuntivi del database (il cosiddetto problema N+1) e prestare attenzione per evitare questo problema. Per altri dettagli, vedere la sezione relativa alle prestazioni.

Caricamento lazy senza proxy

Il caricamento differita senza proxy funziona inserendo il servizio in un'entità ILazyLoader , come descritto in Costruttori di tipi di entità. Ad esempio:

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

Questo metodo non richiede che i tipi di entità vengano ereditati da o le proprietà di navigazione siano virtuali e consentano alle istanze di entità create con new il caricamento differita una volta collegati a un contesto. Tuttavia, è necessario un riferimento al servizio ILazyLoader, che viene definito nel pacchetto Microsoft.EntityFrameworkCore.Abstractions. Questo pacchetto contiene un set minimo di tipi in modo da avere un impatto minimo a seconda di esso. Tuttavia, per evitare completamente a seconda di qualsiasi pacchetto EF Core nei tipi di entità, è possibile inserire il ILazyLoader.Load metodo come delegato. Ad esempio:

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

Il codice precedente usa un metodo di estensione Load per chiarire l'uso del delegato:

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

Nota

Il parametro del costruttore per il delegato di caricamento lazy deve essere chiamato "lazyLoader". La possibilità di configurare l'uso di un nome diverso è pianificata per una versione futura.