Entendo a frustração dos OPs, esse uso do virtual não é para a abstração modelada pela qual o modificador virtual defacto é eficaz.
Se alguém ainda está lutando com isso, eu ofereceria meu ponto de vista, ao tentar manter as soluções simples e o jargão no 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 encaixa no modificador 'virtual', mas há mais para isso.
No Entity Framework, o uso de uma propriedade de navegação virtual permite denotá-la como o equivalente a uma Chave Externa anulável no SQL. Você não precisa ingressar ansiosamente em todas as tabelas com chave ao executar uma consulta, mas quando precisa das informações, elas se tornam orientadas pela demanda.
Mencionei também anulável porque muitas propriedades de navegação não são relevantes a princípio. ou seja, em um cenário de cliente / pedidos, você não precisa esperar até o momento em que um pedido é processado para criar um cliente. Você pode, mas se tiver um processo de várias etapas para conseguir isso, poderá encontrar a necessidade de persistir os dados do cliente para conclusão posterior ou para implantação em pedidos futuros. Se todas as propriedades de navegação foram implementadas, você teria que estabelecer todos os campos de chave estrangeira e relacional ao salvar. Isso realmente apenas coloca os dados de volta na memória, o que anula o papel da persistência.
Portanto, embora possa parecer enigmático na execução real em tempo de execução, eu achei a melhor regra geral a ser usada: se você estiver produzindo dados (lendo em um modelo de exibição ou modelo serializado) e precisar de valores antes das referências, não use virtual; Se o seu escopo estiver coletando dados que podem estar incompletos ou que seja necessário pesquisar e não exija todos os parâmetros de pesquisa concluídos para uma pesquisa, o código fará bom uso da referência, semelhante ao uso das propriedades de valor nulo int? longo?. Além disso, abstrair sua lógica de negócios da coleta de dados até a necessidade de injetá-la traz muitos benefícios de desempenho, semelhantes a instanciar um objeto e iniciá-lo em nulo. O Entity Framework utiliza muita reflexão e dinâmica, o que pode prejudicar o desempenho, e a necessidade de ter um modelo flexível que possa ser dimensionado conforme a demanda é fundamental para gerenciar o desempenho.
Para mim, isso sempre fazia mais sentido do que usar jargões de tecnologia sobrecarregados, como proxies, delegados, manipuladores e outros. Depois de atingir o terceiro ou quarto idioma de programação, pode ficar confuso com eles.