Leniwe ładowanie powiązanych danych
Ładowanie z opóźnieniem za pomocą serwerów proxy
Najprostszym sposobem korzystania z ładowania leniwego jest zainstalowanie pakietu Microsoft.EntityFrameworkCore.Proxies i włączenie go za pomocą wywołania metody UseLazyLoadingProxies
. Przykład:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseLazyLoadingProxies()
.UseSqlServer(myConnectionString);
Lub w przypadku korzystania z polecenia AddDbContext:
.AddDbContext<BloggingContext>(
b => b.UseLazyLoadingProxies()
.UseSqlServer(myConnectionString));
Następnie program EF Core włączy ładowanie opóźnione dla dowolnej właściwości nawigacji, która może zostać zastąpiona — musi to być virtual
i w klasie, z którą można dziedziczyć. Na przykład w następujących jednostkach Post.Blog
właściwości nawigacji i Blog.Posts
zostaną załadowane z opóźnieniem.
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; }
}
Ostrzeżenie
Ładowanie leniwe może spowodować, że wystąpią niepotrzebne dodatkowe przejazdy bazy danych (tak zwany problem N+1) i należy zadbać o to, aby tego uniknąć. Aby uzyskać więcej informacji, zobacz sekcję wydajności.
Ładowanie z opóźnieniem bez serwerów proxy
Ładowanie z opóźnieniem bez serwerów proxy działa przez wstrzyknięcie ILazyLoader
usługi do jednostki, zgodnie z opisem w temacie Entity Type Constructors (Konstruktory typów jednostek). Przykład:
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;
}
}
Ta metoda nie wymaga dziedziczenia typów jednostek z właściwości nawigacji lub jest wirtualna i umożliwia tworzenie wystąpień jednostek z new
opóźnieniem ładowania po dołączeniu do kontekstu. Wymaga jednak odwołania do ILazyLoader
usługi zdefiniowanej w pakiecie Microsoft.EntityFrameworkCore.Abstractions . Ten pakiet zawiera minimalny zestaw typów, dzięki czemu w zależności od niego ma niewielki wpływ. Jednak aby całkowicie uniknąć w zależności od pakietów EF Core w typach jednostek, można wstrzyknąć metodę ILazyLoader.Load
jako delegata. Przykład:
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;
}
}
Powyższy kod używa Load
metody rozszerzenia, aby używać delegata do czyszczenia bitów:
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;
}
}
Uwaga
Parametr konstruktora dla delegata ładowania leniwego musi być nazywany "lazyLoader". Konfiguracja używania innej nazwy niż ta jest planowana dla przyszłej wersji.