it-swarm-pt.tech

Por que usar 'virtual' para propriedades de classe 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 seguinte exemplo de código:

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

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

204
Gary Jones

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 Qual efeito (es) a palavra-chave virtual pode ter no Entity Framework 4.1 POCO Code First? para uma discussão mais completa.

Editar para esclarecer "criar um proxy ao redor": Por "criar um proxy ao redor" estou me referindo especificamente ao que o Entity Framework faz. O Entity Framework requer 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 criação de proxies POCO .
O Entity Framework usa herança para suportar essa funcionalidade, e é por isso que requer que certas propriedades sejam marcadas como virtuais em seus POCOs de classe base. Ele literalmente cria novos tipos que derivam de seus tipos POCO. Portanto, seu POCO está atuando como um tipo de base para as subclasses criadas dinamicamente do Entity Framework. Isso é o que eu quis dizer com "criar um proxy ao redor".

As subclasses 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 compilação estática. E somente se você ativar os recursos de carregamento lento ou de rastreamento de alterações do Entity Framework. Se você optar por nunca usar os recursos de carregamento lento ou de controle 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 por carregar essas propriedades de navegação por conta própria, usando o que o Entity Framework chama de "carregamento rápido" ou recuperando manualmente os tipos relacionados em várias consultas ao banco de dados. Você pode e deve usar o carregamento lento e alterar os recursos de rastreamento para suas propriedades de navegação em muitos cenários.

Se você criasse uma classe autônoma e marcasse propriedades como virtuais e simplesmente construísse e usasse instâncias dessas classes 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 as propriedades seriam marcadas como virtuais

Propriedades como:

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

Não são campos e não devem ser pensados ​​como tal. Estes são chamados de getters e setters e, em tempo de compilação, são convertidos em métodos.

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

É por isso que eles são marcados como virtuais para uso no Entity Framework, ele permite que as classes 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<RSVP> RSVPs;
229
Shan Plourde

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

ATUALIZAÇÃO: Isso não responde à pergunta como é feita atualmente, mas deixarei aqui para qualquer um que esteja procurando uma resposta simples à pergunta original , não-descritiva.

71
M.Babcock

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 encaixa 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 no SQL. Você não precisa aderir a todas as tabelas com chave ao realizar 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. Ou seja, 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 seja necessário persistir os dados do cliente para conclusão posterior ou para implantação em pedidos futuros. 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 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, 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 objeto e iniciá-lo em null. O Entity Framework usa muita reflexão 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 um jargão técnico sobrecarregado, como proxies, delegados, manipuladores e tal. Uma vez que você atingiu a terceira ou quarta programação, pode ficar confuso com isso.

20
Nathan Teague

É 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 recurso interessante 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 banco de dados.

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

13
Hassan Rahman

No contexto do EF, marcar uma propriedade como virtual permite que o EF use o carregamento lento para carregá-lo. Para que o carregamento ocioso funcione, a EF precisa criar um objeto 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.

2
Shakeer Hussain

A palavra-chave virtual é usada para modificar um método, uma propriedade, um indexador ou uma declaração de evento e permite que ela seja substituída em uma classe derivada. Por exemplo, esse método pode ser substituído por qualquer classe que o herde:

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

Você não pode usar o modificador virtual com os modificadores static, abstract, private ou override. O exemplo a seguir mostra uma propriedade virtual:

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";
            }
        }
    }
}
1
FatalMan