Por que usar ‘virtual’ para propriedades de class nas definições de modelo do Entity Framework?

No seguinte blog: http://weblogs.asp.net/scottgu/archive/2010/07/16/code-first-development-with-entity-framework-4.aspx

O blog contém o exemplo de código a seguir:

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 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; } } 

Qual é o propósito de usar o virtual ao definir uma propriedade em uma class? Que efeito isso tem?

Ele permite que o Entity Framework crie um proxy em torno da propriedade virtual para que a propriedade possa suportar carregamento lento e rastreamento de alterações mais eficiente. Veja que efeito (s) a palavra-chave virtual pode ter no código POCO do Entity Framework 4.1 primeiro? para uma discussão mais completa.

Editar para esclarecer “criar um proxy ao redor”: “Criar um proxy ao redor” Estou me referindo especificamente ao que o Entity Framework faz. O Entity Framework exige que suas propriedades de navegação sejam marcadas como virtuais para que o carregamento lento e o rastreamento eficiente de alterações sejam suportados. Veja Requisitos para Criar Proxies POCO .
O Entity Framework usa inheritance para suportar essa funcionalidade, e é por isso que requer que certas propriedades sejam marcadas como virtuais em seus POCOs de class base. Ele literalmente cria novos tipos que derivam de seus tipos POCO. Portanto, seu POCO está atuando como um tipo de base para as subclasss criadas dinamicamente do Entity Framework. Isso é o que eu quis dizer com “criar um proxy ao redor”.

As subclasss criadas dinamicamente que o Entity Framework cria se tornam aparentes ao usar o Entity Framework no tempo de execução, não no tempo de compilation estático. E somente se você ativar os resources de carregamento lento ou de rastreamento de alterações do Entity Framework. Se você optar por nunca usar os resources de carregamento lento ou de rastreamento de alterações do Entity Framework (que não é o padrão), não será necessário declarar nenhuma propriedade de navegação como virtual. Você é responsável pelo carregamento dessas propriedades de navegação, usando o que o Entity Framework chama de “carregamento rápido” ou recuperando manualmente os tipos relacionados em várias consultas ao database. Você pode e deve usar o carregamento lento e alterar os resources de rastreamento de suas propriedades de navegação em muitos cenários.

Se você criasse uma class autônoma e marcasse propriedades como virtuais e simplesmente construísse e usasse instâncias dessas classs em seu próprio aplicativo, completamente fora do escopo do Entity Framework, suas propriedades virtuais não lhe renderiam nada. próprio.

Editar para descrever por que propriedades seriam marcadas como virtuais

Propriedades como:

  public ICollection RSVPs { get; set; } 

Não são campos e não devem ser considerados como tal. Estes são chamados de getters e setters e, em tempo de compilation, são convertidos em methods.

 //Internally the code looks more like this: public ICollection get_RSVPs() { return _RSVPs; } public void set_RSVPs(RSVP value) { _RSVPs = value; } private RSVP _RSVPs; 

É por isso que eles são marcados como virtuais para uso no Entity Framework, ele permite que as classs criadas dinamicamente substituam as funções get e set geradas internamente. Se os getter / setters da propriedade de navegação estiverem funcionando para você no uso do Entity Framework, tente revisá-los apenas para propriedades, recompile e veja se o Entity Framework ainda pode funcionar corretamente:

  public virtual ICollection RSVPs; 

A palavra-chave virtual em C # permite que um método ou propriedade seja substituído por classs filhas. Para mais informações, consulte a documentação do MSDN sobre a palavra-chave ‘virtual’

ATUALIZAÇÃO: É evidente que a minha resposta não está alinhada com a que era esperada, dadas as circunstâncias da questão, mas deixarei aqui para quem procura uma resposta simples à pergunta não descritiva original pedida.

Eu entendo a frustração dos OPs, este uso do virtual não é para a abstração modelada que o modificador virtual defacto é efetivo.

Se algum ainda estiver lutando com isso, eu ofereço meu ponto de vista, enquanto tento manter as soluções simples e o jargão ao mínimo:

O Entity Framework em uma peça simples utiliza carregamento lento, o que equivale a preparar algo para execução futura. Isso se encheckbox no modificador ‘virtual’, mas há mais nisso.

No Entity Framework, o uso de uma propriedade de navegação virtual permite denotá-lo como o equivalente a uma chave estrangeira anulável em SQL. Você não precisa aderir a todas as tabelas com chave ao executar uma consulta, mas quando precisar delas, elas se tornam orientadas pela demanda.

Também mencionei nullable porque muitas propriedades de navegação não são relevantes no início. Por exemplo, em um cenário de pedidos / cliente, você não precisa esperar até o momento em que um pedido é processado para criar um cliente. Você pode, mas se tivesse um processo em vários estágios para conseguir isso, talvez fosse necessário persistir os dados do cliente para uma conclusão posterior ou para implantação em futuros pedidos. Se todas as propriedades de navegação fossem implementadas, você teria que estabelecer cada chave estrangeira e campo relacional no salvamento. Isso realmente apenas coloca os dados de volta na memory, o que anula o papel da persistência.

Assim, embora possa parecer enigmático na execução real em tempo de execução, descobri que a melhor regra prática a ser usada seria: se você estiver transmitindo dados (lendo em um Modelo de Visualização ou Modelo Serializável) e precisar de valores antes das referências, não use virtual; Se o seu escopo estiver coletando dados que podem estar incompletos ou uma necessidade de pesquisar e não exigir que todos os parâmetros de pesquisa sejam concluídos para uma pesquisa, o código fará bom uso da referência, semelhante ao uso de propriedades de valor anuláveis ​​int? longo?. Além disso, abstrair sua lógica de negócios de sua coleta de dados até a necessidade de injetá-la tem muitos benefícios de desempenho, como instanciar um object e iniciá-lo em null. O Entity Framework usa muita reflection e dinâmica, o que pode degradar o desempenho, e a necessidade de ter um modelo flexível que possa escalar para a demanda é fundamental para gerenciar o desempenho.

Para mim, isso sempre fazia mais sentido do que usar o jargão de tecnologia sobrecarregado como proxies, delegates, manipuladores e tal. Uma vez que você acertar sua terceira ou quarta programação, pode ficar confuso com isso.

É muito comum definir as propriedades de navegação em um modelo como virtuais. Quando uma propriedade de navegação é definida como virtual, ela pode aproveitar certas funcionalidades do Entity Framework. O mais comum é o carregamento lento.

Carregamento preguiçoso é um bom recurso de muitos ORMs porque permite acessar dinamicamente dados relacionados de um modelo. Ele não buscará os dados relacionados desnecessariamente até que seja realmente acessado, reduzindo assim a consulta inicial dos dados do database.

Do livro “ASP.NET MVC 5 com Bootstrap e Knockout.js”

No contexto da EF, marcar uma propriedade como virtual permite que a EF use o carregamento lento para carregá-la. Para que o carregamento ocioso funcione, a EF precisa criar um object proxy que substitua suas propriedades virtuais por uma implementação que carregue a entidade referenciada quando for acessada pela primeira vez. Se você não marcar a propriedade como virtual, o carregamento lento não funcionará com ela.