Lazy Loading zugehöriger Daten
Lazy Loading mit Proxys
Die einfachste Möglichkeit für die Verwendung von Lazy Loading besteht in der Installation des Pakets Microsoft.EntityFrameworkCore.Proxies und der Aktivierung dieses Pakets durch Aufrufen von UseLazyLoadingProxies
. Beispiel:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseLazyLoadingProxies()
.UseSqlServer(myConnectionString);
Oder bei Verwendung von AddDbContext:
.AddDbContext<BloggingContext>(
b => b.UseLazyLoadingProxies()
.UseSqlServer(myConnectionString));
EF Core aktiviert Lazy Loading anschließend für beliebige überschreibbare Navigationseigenschaften – diese müssen virtual
und in einer Klasse enthalten sein, aus der sie geerbt werden können. In den folgenden Entitäten wird beispielsweise Lazy Loading für die Navigationseigenschaften Post.Blog
und Blog.Posts
durchgeführt.
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; }
}
Warnung
Verzögertes Laden kann zu unnötigen zusätzlichen Datenbankroundtrips führen (das sogenannte N+1-Problem). Sie sollten Maßnahmen ergreifen, um dies zu vermeiden. Weitere Details finden Sie im Abschnitt Vermeiden von verzögertem Laden.
Lazy Loading ohne Proxys
Beim Lazy Loading ohne Proxys wird der Dienst ILazyLoader
, wie unter Entitätstypenkonstruktoren beschrieben, in eine Entität eingefügt. Beispiel:
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;
}
}
Für diese Methode ist nicht erforderlich, dass aus Entitätstypen vererbt wird oder Navigationseigenschaften „virtual“ sind. Mit new
erstellte Entitätsinstanzen können Lazy Loading ausführen, sobald sie einem Kontext angefügt wurden. Erforderlich ist ein Verweis auf den ILazyLoader
-Dienst, der im Microsoft.EntityFrameworkCore.Abstractions-Paket definiert ist. Dieses Paket enthält eine minimale Gruppe von Typen, sodass die Abhängigkeit davon kaum Auswirkungen hat. Es ist jedoch möglich, die Methode ILazyLoader.Load
als Delegat einzufügen, um eine Abhängigkeit von EF Core-Paketen in den Entitätstypen gänzlich zu vermeiden. Beispiel:
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;
}
}
Der oben stehende Code verwendet eine Load
-Erweiterungsmethode, um die Verwendung des Delegaten sauberer zu gestalten:
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;
}
}
Hinweis
Der Konstruktorparameter für den Lazy Loading-Delegaten muss als „lazyLoader“ bezeichnet werden. Eine Konfiguration für die Verwendung eines anderen Namens ist für ein zukünftiges Release geplant.