関連データの遅延読み込み
プロキシを使用した遅延読み込み
遅延読み込みを使用するには、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.Blog
および Blog.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;
}
}
Note
遅延読み込みデリゲートのコンストラクター パラメーターは、"lazyLoader" と指定する必要があります。 これとは別の名前を使用する構成が今後のリリースで計画されています。
.NET