Зачем использовать "virtual" для свойств класса в определениях модели 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 при определении свойства в классе? Какой эффект у него есть?

Ответ 1

Он позволяет 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/seters для навигационных свойств работают для вас в вашем использовании Entity Framework, попробуйте пересмотреть их только на свойства, перекомпилировать и посмотреть, сможет ли Entity Framework функционировать должным образом:

 public virtual ICollection<RSVP> RSVPs;

Ответ 2

virtual ключевое слово в С# позволяет методу или свойству быть переопределенным дочерними классами. Дополнительную информацию см. В документации MSDN по ключевому слову "virtual".

ОБНОВЛЕНИЕ: Это не отвечает на вопрос, как в настоящее время задается, но я оставлю это здесь для любого, кто ищет простой ответ на оригинальный, не описательный вопрос, заданный.

Ответ 3

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

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

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

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

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

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

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

Ответ 4

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

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

Из книги "ASP.NET MVC 5 с Bootstrap и Knockout.js"

Ответ 5

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

Ответ 6

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

public virtual double Area() 
{
    return x * y;
}

Вы не можете использовать виртуальный модификатор с модификаторами static, abstract, private или override. В следующем примере показано виртуальное свойство:

class MyBaseClass
{
    // virtual auto-implemented property. Overrides can only
    // provide specialized behavior if they implement get and set accessors.
    public virtual string Name { get; set; }

    // ordinary virtual property with backing field
    private int num;
    public virtual int Number
    {
        get { return num; }
        set { num = value; }
    }
}


class MyDerivedClass : MyBaseClass
{
    private string name;

    // Override auto-implemented property with ordinary property
    // to provide specialized accessor behavior.
    public override string Name
    {
        get
        {
            return name;
        }
        set
        {
            if (value != String.Empty)
            {
                name = value;
            }
            else
            {
                name = "Unknown";
            }
        }
    }
}