Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Platforma Entity Framework obsługuje trzy sposoby ładowania powiązanych danych — ładowanie chciwe, ładowanie leniwe i ładowanie jawne. Techniki przedstawione w tym temacie mają zastosowanie w równym stopniu do modeli utworzonych przy użyciu funkcji Code First i projektanta EF.
Z niecierpliwością ładują
Chętne ładowanie to proces, w którym zapytanie dla jednego typu jednostki ładuje również powiązane jednostki w ramach zapytania. Wcześniejsze ładowanie jest osiągane przy użyciu metody Include. Na przykład poniższe zapytania będą ładować blogi i wszystkie wpisy powiązane z każdym blogiem.
using (var context = new BloggingContext())
{
// Load all blogs and related posts.
var blogs1 = context.Blogs
.Include(b => b.Posts)
.ToList();
// Load one blog and its related posts.
var blog1 = context.Blogs
.Where(b => b.Name == "ADO.NET Blog")
.Include(b => b.Posts)
.FirstOrDefault();
// Load all blogs and related posts
// using a string to specify the relationship.
var blogs2 = context.Blogs
.Include("Posts")
.ToList();
// Load one blog and its related posts
// using a string to specify the relationship.
var blog2 = context.Blogs
.Where(b => b.Name == "ADO.NET Blog")
.Include("Posts")
.FirstOrDefault();
}
Uwaga / Notatka
Include to metoda rozszerzenia w przestrzeni nazw System.Data.Entity, dlatego upewnij się, że używasz tej przestrzeni nazw.
Z niecierpliwością ładują wiele poziomów
Można również chętnie załadować wiele poziomów powiązanych jednostek. Poniższe zapytania pokazują przykłady, jak to zrobić zarówno dla właściwości nawigacji w kolekcjach, jak i tych dotyczących odwołań.
using (var context = new BloggingContext())
{
// Load all blogs, all related posts, and all related comments.
var blogs1 = context.Blogs
.Include(b => b.Posts.Select(p => p.Comments))
.ToList();
// Load all users, their related profiles, and related avatar.
var users1 = context.Users
.Include(u => u.Profile.Avatar)
.ToList();
// Load all blogs, all related posts, and all related comments
// using a string to specify the relationships.
var blogs2 = context.Blogs
.Include("Posts.Comments")
.ToList();
// Load all users, their related profiles, and related avatar
// using a string to specify the relationships.
var users2 = context.Users
.Include("Profile.Avatar")
.ToList();
}
Uwaga / Notatka
Obecnie nie można filtrować, które powiązane jednostki są ładowane. Dołączanie zawsze spowoduje wprowadzenie wszystkich powiązanych jednostek.
Późne ładowanie
Ładowanie opóźnione to proces, w którym jednostka lub kolekcja jednostek jest automatycznie ładowana z bazy danych przy pierwszym uzyskiwaniu dostępu do właściwości odwołującej się do jednostki/jednostek. W przypadku korzystania z typów jednostek POCO, ładowanie z opóźnieniem (lazy loading) jest osiągane przez utworzenie wystąpień pochodnych typów proxy, a następnie zastąpienie właściwości wirtualnych w celu dodania mechanizmu ładowania. Na przykład w przypadku korzystania z poniższej klasy jednostki Blog powiązane wpisy zostaną załadowane przy pierwszym uzyskiwaniu dostępu do właściwości nawigacji Posty:
public class Blog
{
public int BlogId { get; set; }
public string Name { get; set; }
public string Url { get; set; }
public string Tags { get; set; }
public virtual ICollection<Post> Posts { get; set; }
}
Wyłącz leniwe ładowanie dla serializacji
Ładowanie leniwe i serializacja nie współgrają dobrze, a jeśli nie jesteś ostrożny, możesz wykonać zapytanie dla całej bazy danych tylko dlatego, że ładowanie leniwe jest włączone. Większość serializatorów działa, zapewniając dostęp do każdej właściwości instancji typu. Dostęp do właściwości wyzwala ładowanie leniwe, więc więcej jednostek jest serializowanych. Uzyskuje się dostęp do właściwości tych encji, a jeszcze więcej encji jest ładowanych. Dobrym rozwiązaniem jest wyłączenie ładowania z opóźnieniem przed serializacji jednostki. W poniższych sekcjach pokazano, jak to zrobić.
Wyłączanie leniwego ładowania dla określonych właściwości nawigacyjnych
Ładowanie leniwe kolekcji Posty można wyłączyć, ustawiając właściwość Posty jako niewirtualną.
public class Blog
{
public int BlogId { get; set; }
public string Name { get; set; }
public string Url { get; set; }
public string Tags { get; set; }
public ICollection<Post> Posts { get; set; }
}
Ładowanie kolekcji Postów można nadal osiągnąć przy użyciu eager loading (zobacz Eagerly Loading powyżej) lub metoda Load (zobacz Explicitly Loading poniżej).
Wyłącz ładowanie leniwe dla wszystkich jednostek
Ładowanie leniwe można wyłączyć dla wszystkich elementów w kontekście, ustawiając flagę we właściwości Configuration. Przykład:
public class BloggingContext : DbContext
{
public BloggingContext()
{
this.Configuration.LazyLoadingEnabled = false;
}
}
Ładowanie powiązanych jednostek można nadal osiągnąć przy użyciu ładowania natychmiastowego (zobacz Ładowanie natychmiastowe powyżej) lub funkcji Load (zobacz Jawne ładowanie poniżej).
Jawne ładowanie
Nawet przy wyłączonym opóźnionym ładowaniu nadal możliwe jest leniwe załadowanie powiązanych encji, ale należy to zrobić przez jawne wywołanie. W tym celu należy użyć metody Load we wpisie powiązanej jednostki. Przykład:
using (var context = new BloggingContext())
{
var post = context.Posts.Find(2);
// Load the blog related to a given post.
context.Entry(post).Reference(p => p.Blog).Load();
// Load the blog related to a given post using a string.
context.Entry(post).Reference("Blog").Load();
var blog = context.Blogs.Find(1);
// Load the posts related to a given blog.
context.Entry(blog).Collection(p => p.Posts).Load();
// Load the posts related to a given blog
// using a string to specify the relationship.
context.Entry(blog).Collection("Posts").Load();
}
Uwaga / Notatka
Metoda Reference powinna być używana, gdy jednostka ma właściwość nawigacji do innej pojedynczej jednostki. Z drugiej strony metoda Collection powinna być używana, gdy jednostka ma właściwość nawigacji do kolekcji innych jednostek.
Stosowanie filtrów podczas jawnego ładowania powiązanych jednostek
Metoda Query zapewnia dostęp do bazowego zapytania, które będzie używane przez program Entity Framework podczas ładowania powiązanych jednostek. Następnie można użyć LINQ, aby zastosować filtry do zapytania, przed jego wykonaniem za pomocą wywołania metody rozszerzenia LINQ, takiej jak ToList, Load itp. Metoda Query może być używana zarówno z właściwościami nawigacyjnymi odniesienia, jak i z właściwościami nawigacyjnymi kolekcji, ale jest najbardziej przydatna w przypadku kolekcji, gdzie może służyć do ładowania tylko części kolekcji. Przykład:
using (var context = new BloggingContext())
{
var blog = context.Blogs.Find(1);
// Load the posts with the 'entity-framework' tag related to a given blog.
context.Entry(blog)
.Collection(b => b.Posts)
.Query()
.Where(p => p.Tags.Contains("entity-framework"))
.Load();
// Load the posts with the 'entity-framework' tag related to a given blog
// using a string to specify the relationship.
context.Entry(blog)
.Collection("Posts")
.Query()
.Where(p => p.Tags.Contains("entity-framework"))
.Load();
}
W przypadku korzystania z metody Query najlepiej jest zwykle wyłączyć ładowanie leniwe dla właściwości nawigacji. Dzieje się tak dlatego, że w przeciwnym razie cała kolekcja może zostać załadowana automatycznie przez mechanizm ładowania z opóźnieniem (zarówno przed, jak i po wykonaniu filtrowanego zapytania).
Uwaga / Notatka
Chociaż relację można określić jako ciąg znaków zamiast wyrażenia lambda, zwracany obiekt IQueryable nie jest ogólny, gdy używa się ciągu znaków i dlatego metoda rzutowania jest zwykle potrzebna, zanim będzie można zrobić z nim coś użytecznego.
Używanie zapytania do zliczania powiązanych jednostek bez ich ładowania
Czasami warto wiedzieć, ile jednostek jest powiązanych z inną jednostką w bazie danych bez faktycznego ponoszenia kosztów ładowania wszystkich tych jednostek. W tym celu można użyć metody Query z metodą LINQ Count. Przykład:
using (var context = new BloggingContext())
{
var blog = context.Blogs.Find(1);
// Count how many posts the blog has.
var postCount = context.Entry(blog)
.Collection(b => b.Posts)
.Query()
.Count();
}