Зачем использовать «виртуальный» для свойств класса в определениях модели Entity Framework? - PullRequest
205 голосов
/ 17 декабря 2011

В следующем блоге: 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 при определении свойства в классе?Какой эффект это имеет?

Ответы [ 6 ]

231 голосов
/ 17 декабря 2011

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

Правка для уточнения "создать прокси вокруг": Под «созданием прокси вокруг» я имею в виду конкретно то, что делает Entity Framework.Entity Framework требует, чтобы ваши навигационные свойства были помечены как виртуальные, чтобы поддерживалась отложенная загрузка и эффективное отслеживание изменений.См. Требования для создания прокси-серверов POCO .
. Entity Framework использует наследование для поддержки этой функции, поэтому требует, чтобы определенные свойства были помечены как виртуальные в POCO базового класса.Он буквально создает новые типы, которые происходят от ваших типов 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.Если ваши средства получения / установки свойств навигации работают на вас при использовании Entity Framework, попробуйте изменить их на просто свойства, перекомпилировать и посмотреть, может ли Entity Framework по-прежнему функционировать должным образом:

 public virtual ICollection<RSVP> RSVPs;
71 голосов
/ 17 декабря 2011

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

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

20 голосов
/ 19 февраля 2015

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

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

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

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

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

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

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

13 голосов
/ 02 марта 2016

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

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

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

2 голосов
/ 27 февраля 2018

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

1 голос
/ 12 апреля 2019

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

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";
            }
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...