延遲載入相關資料

使用 Proxy 延遲載入

使用消極式載入的最簡單方式是安裝 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 問題),並應小心避免這種情況。 如需詳細資訊, 請參閱效能一節

沒有 Proxy 的消極式載入

不具 Proxy 的延遲載入可藉由將服務插入 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 建立的實體實例在附加至內容之後延遲載入。 不過,它需要對 ILazyLoader 服務的參考,這在 Microsoft.EntityFrameworkCore.Abstractions 套件中定義。 此套件包含一組最少的類型,因此會根據其影響不大。 不過,若要完全避免視實體類型中的任何 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"。 預計將於未來版本中推出使用與此不同之名稱的設定。