Какой эффект могут оказать виртуальные ключевые слова в Entity Framework 4.1 POCO Code First?

229

Влияет ли virtualключевое слово на свойства в EF Code First ?. Может ли кто-нибудь описать все его последствия в разных ситуациях?

Например, я знаю, что он может управлять отложенной загрузкой - если вы используете виртуальное ключевое слово в свойстве отношения ICollection / one-to-many, оно будет загружаться с отложенной загрузкой по умолчанию, тогда как если вы пропустите виртуальное ключевое слово, оно будет быть загруженным.

Какие еще эффекты могут virtualиметь ключевое слово в EF с сущностями POCO ?. Должен ли я сделать его по умолчанию для использования virtualво всех моих свойствах, или по умолчанию не использовать его?

Скотт Стаффорд
источник

Ответы:

194

До сих пор я знаю об этих эффектах.

  • Ленивая загрузка : любые virtualICollections будут загружаться с отложенной загрузкой, если вы специально не отметите их иначе.
  • Более эффективное отслеживание изменений . Если вы удовлетворяете всем следующим требованиям, то отслеживание изменений может использовать более эффективный метод, подключая ваши виртуальные свойства. По ссылке:

    Чтобы получить прокси отслеживания изменений, основное правило заключается в том, что ваш класс должен быть общедоступным, неабстрактным или незапечатанным. Ваш класс должен также реализовать общедоступные виртуальные методы получения / установки для всех сохраняемых свойств. Наконец, вы должны объявить ICollection<T>только свойства навигации на основе коллекции . Они не могут быть конкретной реализацией или другим интерфейсом, который является производным ICollection<T>(отличие от прокси с отложенной загрузкой)

Другая полезная ссылка, описывающая это, - Требования MSDN для создания прокси POCO .

Скотт Стаффорд
источник
52
Нет другой причины делать свойства виртуальными. Свойства навигации помечены как виртуальные для отложенной загрузки, а скалярные свойства помечены как виртуальные для отслеживания изменений.
Ладислав Мрнка
10
что такое свойства навигации и что такое скалярные свойства?
Абид Али
9
@AbidAli: Я считаю, что свойство навигации - это внешний ключ (тип класса сущности) или отношение один ко многим (типа ICollection <>). Скалярное свойство - это базовый тип (int, string, ..) или ComplexType (который является просто структурой базовых типов).
Скотт Стаффорд
2
" public virtual byte[] bigData { get; set; }" Ленивая загрузка?
AechoLiu
9
Байты [] будут загружены с нетерпением, только внешние ключи могут быть ленивыми. Если вы не хотите извлекать этот столбец, никогда не извлекайте всю запись - просто .Select(a=>new { fields you want }).
Скотт Стаффорд
63

Это виртуальное ключевое слово связано с темой загрузки данных из структуры сущностей (отложенная загрузка, полная загрузка и явная загрузка).

Вы должны использовать виртуальное ключевое слово, когда вы хотите загрузить данные с отложенной загрузкой.

отложенная загрузка - это процесс, при котором сущность или коллекция сущностей автоматически загружаются из базы данных при первом обращении к ней.

Например, при использовании класса сущности Блог, определенного ниже, связанные сообщения будут загружаться при первом обращении к свойству навигации по сообщениям:

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 не виртуальным.

если отложенная загрузка отключена, загрузка коллекции Posts все еще может быть достигнута с помощью активной загрузки (с помощью метода Include) или явной загрузки связанных объектов (с помощью метода Load).

Жадно загружается:

using (var context = new BloggingContext()) 
{ 
    // Load all blogs and related posts 
    var blogs1 = context.Blogs 
                          .Include(b => b.Posts) 
                          .ToList(); 
}

Явно загрузка:

using (var context = new BloggingContext()) 
{ 
    var blog = context.Blogs.Find(1); 

    // Load the posts related to a given blog 
    context.Entry(blog).Collection(p => p.Posts).Load(); 
}
парса
источник
1
Как избежать проблемы N + 1 при использовании виртуальных (ленивая загрузка)? Например, context.Blogs.ToList (); тогда он не будет объединять таблицы, и он будет выполнять запрос select столько же, сколько и количество блогов.
Эксперт хочет быть
1
@Expertwannabe Даже если вы используете отложенную загрузку, вы все равно можете явно запросить активную загрузку с вызовом Include().
Монсеньор