Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Entity Framework поддерживает три способа загрузки связанных данных — жадной загрузки, отложенной загрузки и явной загрузки. Методы, показанные в этом разделе, применяются одинаково к моделям, созданным с помощью code First и ef Designer.
Быстрая загрузка
Жадная загрузка — это процесс, в котором запрос для одного типа сущности также загружает связанные сущности в ходе выполнения запроса. Жадная загрузка достигается с помощью метода Include. Например, приведенные ниже запросы загружают блоги и все записи, связанные с каждым блогом.
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();
}
Замечание
Include — это метод расширения в пространстве имен System.Data.Entity, поэтому убедитесь, что вы используете это пространство имен.
Ускоренная загрузка нескольких уровней
Также можно с нетерпением загружать несколько уровней связанных сущностей. В приведенных ниже запросах показаны примеры того, как это сделать для свойств коллекции и ссылочной навигации.
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();
}
Замечание
В настоящее время невозможно отфильтровать, какие связанные сущности загружаются. Функция включения всегда будет охватывать все связанные сущности.
Отложенная загрузка
Отложенная загрузка — это процесс, при котором сущность или коллекция сущностей автоматически загружаются из базы данных при первом доступе к свойству, ссылающемся на сущность или сущности. При использовании типов сущностей POCO отложенная загрузка осуществляется путем создания экземпляров производных типов прокси и переопределения виртуальных свойств для добавления крючка загрузки. Например, при использовании класса сущности блога, определенного ниже, связанные записи будут загружены при первом доступе к свойству навигации Post:
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; }
}
Отключение отложенной загрузки для сериализации
Отложенная загрузка и сериализация не смешиваются хорошо, и если вы не осторожны, вы можете в конечном итоге запрашивать всю базу данных только потому, что отложенная загрузка включена. Большинство сериализаторов работают путем доступа к каждому свойству в экземпляре типа. Доступ к свойствам активирует отложенную загрузку, поэтому больше сущностей сериализуются. Доступ к свойствам этих сущностей осуществляется, и загружаются еще больше сущностей. Рекомендуется отключить отложенную загрузку перед сериализацией сущности, чтобы избежать неожиданных ошибок. В следующих разделах показано, как это сделать.
Отключение отложенной загрузки для определенных свойств навигации
Отложенная загрузка коллекции "Posts" может быть отключена, сделав свойство "Posts" невиртуальным.
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; }
}
Загрузка коллекции "Записи" по-прежнему может быть достигнута с помощью нетерпеливой загрузки (см. Нетерпеливая загрузка выше) или метода Load (см. Явная загрузка ниже).
Отключение отложенной загрузки для всех сущностей
Отложенная загрузка может быть отключена для всех сущностей в контексте, задав флаг для свойства Configuration. Рассмотрим пример.
public class BloggingContext : DbContext
{
public BloggingContext()
{
this.Configuration.LazyLoadingEnabled = false;
}
}
Загрузка связанных сущностей по-прежнему может быть достигнута с помощью жадной загрузки (см. 'Жадная загрузка' выше) или метода Load (см. Явная загрузка ниже).
Явная загрузка
Даже при отключенной отложенной загрузке по-прежнему можно загрузить связанные сущности отложенно, но для этого необходим явный вызов. Для этого используется метод Load для записи связанной сущности. Рассмотрим пример.
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();
}
Замечание
Метод Reference следует использовать, если сущность имеет свойство навигации для другой отдельной сущности. С другой стороны, метод Collection должен использоваться, если сущность имеет свойство навигации в коллекцию других сущностей.
Применение фильтров при явной загрузке связанных сущностей
Метод Query предоставляет доступ к базовому запросу, который Entity Framework будет использовать при загрузке связанных сущностей. Затем можно использовать LINQ для применения фильтров к запросу перед выполнением вызова метода расширения LINQ, такого как ToList, Load и т. д. Метод Query можно использовать как со свойствами навигации ссылок, так и для коллекции, но наиболее полезно для коллекций, где его можно использовать для загрузки только части коллекции. Рассмотрим пример.
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();
}
При использовании метода Query обычно рекомендуется отключить отложенную загрузку для свойства навигации. Это связано с тем, что в противном случае вся коллекция может загружаться автоматически с помощью отложенного механизма загрузки либо до, либо после выполнения отфильтрованного запроса.
Замечание
Хотя связь может быть указана как строка вместо использования лямбда-выражения, возвращаемый IQueryable не является объектом обобщённого типа при использовании строки, и поэтому метод Cast обычно необходим, прежде чем выполнить с ним любые полезные действия.
Использование запроса для подсчета связанных сущностей без их загрузки
Иногда полезно знать, сколько сущностей связано с другой сущностью в базе данных без фактической загрузки всех этих сущностей. Для этого можно использовать метод Query с методом LINQ Count. Рассмотрим пример.
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();
}