Зачем использовать "виртуальный" для свойств класса в определениях модели Entity Framework?


в следующем блоге: http://weblogs.asp.net/scottgu/archive/2010/07/16/code-first-development-with-entity-framework-4.aspx

блог содержит следующий код:

public class Dinner
{
   public int DinnerID { get; set; }
   public string Title { get; set; }
   public DateTime EventDate { get; set; }
   public string Address { get; set; }
   public string HostedBy { get; set; }
   public virtual ICollection<RSVP> RSVPs { get; set; }
}

public class RSVP
{
   public int RsvpID { get; set; }
   public int DinnerID { get; set; }
   public string AttendeeEmail { get; set; }
   public virtual Dinner Dinner { get; set; }
}

какова цель использования virtual при определении свойства в классе? Какой эффект это оказывает?

5 193

5 ответов:

Это позволяет Entity Framework создать прокси-сервер вокруг виртуального свойства, чтобы свойство могло поддерживать ленивую загрузку и более эффективное отслеживание изменений. Смотрите какой эффект(ы) может иметь виртуальное ключевое слово в Entity Framework 4.1 POCO Code First? для более подробного обсуждения.

изменить, чтобы уточнить "создать прокси вокруг": Под "созданием прокси-сервера" я имею в виду именно то, что делает Entity Framework. платформа Entity Framework требуется, чтобы ваши свойства навигации были помечены как виртуальные, чтобы поддерживалась ленивая загрузка и эффективное отслеживание изменений. Смотрите требования к созданию Прокси POCO.
Платформа Entity Framework использует наследование для поддержки этой функции, поэтому она требует, чтобы определенные свойства были помечены как виртуальные в базовом классе POCOs. Он буквально создает новые типы, производные от ваших типов POCO. Таким образом, ваш POCO действует как базовый тип для динамической структуры Entity Framework созданы подклассы. Вот что я имел в виду под "создать прокси вокруг".

динамически создаваемые подклассы, создаваемые Entity Framework, становятся очевидными при использовании Entity Framework во время выполнения, а не во время статической компиляции. И только если вы включите функции отложенной загрузки или отслеживания изменений Entity Framework. Если вы решите никогда не использовать функции отложенной загрузки или отслеживания изменений Entity Framework (что не является значением по умолчанию) , вам не нужно объявлять ни один из ваших свойства навигации как виртуальные. Затем вы сами отвечаете за загрузку этих свойств навигации, либо используя то, что Entity Framework называет "нетерпеливой загрузкой", либо вручную извлекая связанные типы из нескольких запросов к базе данных. Однако вы можете и должны использовать функции отложенной загрузки и отслеживания изменений для своих свойств навигации во многих сценариях.

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

изменить, чтобы описать, почему свойства будут помечены как виртуальные

свойства, такие как:

 public ICollection<RSVP> RSVPs { get; set; }

не поля и не должны рассматриваться как таковые. Они называются геттерами и сеттерами и во время компиляции преобразуются в методы.

//Internally the code looks more like this:
public ICollection<RSVP> get_RSVPs()
{
    return _RSVPs;
}

public void set_RSVPs(RSVP value)
{
    _RSVPs = value;
}

private RSVP _RSVPs;

вот почему они помечены как виртуальные для использования в Entity Framework, это позволяет динамически создаваемым классам переопределять внутренне созданные get и set функции. Если ваши навигационные свойства getter / setters работают для вас в вашем использовании Entity Framework, попробуйте изменить их на просто свойства, перекомпилировать и посмотреть, может ли Entity Framework по-прежнему функционировать должным образом:

 public virtual ICollection<RSVP> RSVPs;

на virtual ключевое слово в C# позволяет переопределять метод или свойство дочерними классами. Для получения дополнительной информации, пожалуйста, обратитесь к документация MSDN по ключевому слову 'virtual'

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

Я понимаю разочарование OPs, это использование virtual не для шаблонной абстракции, для которой эффективен виртуальный модификатор defacto.

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

Entity Framework в простой части использует ленивую загрузку, что эквивалентно подготовке чего-то для будущего выполнения. Это соответствует "виртуальному" модификатору, но там это еще не все.

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

Я также упомянул nullable, потому что многие свойства навигации сначала не актуальны. т. е. в сценарии клиент / заказы вам не нужно ждать до момента заказ обрабатывается для создания клиента. Вы можете, но если бы у вас был многоступенчатый процесс для достижения этого, вы могли бы найти необходимость остаются данные клиента для более позднего завершения или для развертывания в будущих заказах. Если бы все свойства nav были реализованы, вам пришлось бы установить каждый внешний ключ и реляционное поле на сохранение. Это действительно просто возвращает данные обратно в память, что побеждает роль настойчивости.

Так что пока это может показаться загадочным в фактическое выполнение во время выполнения, я нашел лучшее эмпирическое правило, чтобы использовать будет: если вы не вывода данных (чтение в модели представления или модели сериализуемый) и нужно значения до ссылок, не использовать виртуальные; если ваша сфера является сбор данных, которые могут быть неполными или нужно искать и не требуется каждый параметр поиска завершенный для поиска и ими можно будет воспользоваться ссылкой, как при использовании допускающие значение свойства типа int? долго?. Кроме того, абстрагирование бизнес-логики от сбор данных до тех пор, пока не возникнет необходимость его внедрения, имеет много преимуществ в производительности, подобно созданию экземпляра объекта и запуску его с нуля. Entity Framework использует много рефлексии и динамики, которые могут ухудшить производительность, и необходимость иметь гибкую модель, которая может масштабироваться по требованию, имеет решающее значение для управления производительностью.

для меня это всегда имело больше смысла, чем использование перегруженного технического жаргона, такого как прокси, делегаты, обработчики и т. д. Как только вы нажмете третий или четвертый Программирование Лэнг, это может стать грязным с ними.

Это довольно часто, чтобы определить навигационные свойства в модели, чтобы быть виртуальной. Если свойство навигации определено как виртуальное, оно может воспользуйтесь определенными функциональными возможностями Entity Framework. Этот наиболее распространенным является ленивая загрузка.

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

из книги "ASP.NET MVC 5 с Бутстрапом и нокаутом.ОАО"

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