Perché utilizzare “virtuale” per le proprietà di class nelle definizioni del modello di Entity Framework?

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

Il blog contiene il seguente codice di esempio:

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 è lo scopo dell’utilizzo virtual quando si definisce una proprietà in una class? Che effetto ha?

Consente a Entity Framework di creare un proxy attorno alla proprietà virtuale in modo che la proprietà possa supportare il caricamento lento e un monitoraggio delle modifiche più efficiente. Vedere Quali effetti può avere la parola chiave virtuale nel codice POCO di Entity Framework 4.1? per una discussione più approfondita.

Modifica per chiarire “creare un proxy intorno”: con “crea un proxy intorno” mi riferisco specificamente a ciò che fa il framework Entity. Entity Framework richiede che le proprietà di navigazione siano contrassegnate come virtuali in modo che il caricamento lento e il rilevamento efficiente delle modifiche siano supportati. Vedi Requisiti per la creazione di proxy POCO .
Entity Framework utilizza l’ereditarietà per supportare questa funzionalità, motivo per cui richiede che determinate proprietà vengano contrassegnate come virtuali nei POCO della class base. Crea letteralmente nuovi tipi che derivano dai tuoi tipi POCO. Quindi il tuo POCO agisce come un tipo di base per le sottoclassi create dynamicmente dal Entity Framework. Questo è ciò che intendevo per “creare un proxy in giro”.

Le sottoclassi create dynamicmente create da Entity Framework diventano evidenti quando si utilizza Entity Framework in fase di runtime, non in fase di compilazione statica. E solo se si abilita il pigro caricamento o le funzionalità di tracciamento delle modifiche di Entity Framework. Se si sceglie di non utilizzare mai le funzionalità di caricamento lazy o di modifica delle modifiche di Entity Framework (che non è l’impostazione predefinita), non è necessario dichiarare virtuali le proprietà di navigazione. Successivamente, sei responsabile del caricamento di tali proprietà di navigazione, utilizzando ciò che il framework Entity definisce “caricamento ansioso” o recuperando manualmente i tipi correlati su più query di database. Tuttavia, puoi e dovresti usare il caricamento lazy e modificare le funzionalità di tracciamento per le tue proprietà di navigazione in molti scenari.

Se dovessi creare una class autonoma e contrassegnare le proprietà come virtuali e semplicemente build e utilizzare istanze di tali classi nella tua applicazione, completamente al di fuori dell’ambito di Entity Framework, le tue proprietà virtuali non ti darebbero nulla proprio.

Modifica per descrivere il motivo per cui le proprietà sarebbero contrassegnate come virtuali

Proprietà come:

  public ICollection RSVPs { get; set; } 

Non sono campi e non dovrebbero essere pensati come tali. Questi sono chiamati getter e setter e al momento della compilazione, vengono convertiti in metodi.

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

Questo è il motivo per cui sono contrassegnati come virtuali per l’uso in Entity Framework, consente alle classi create dynamicmente di sovrascrivere le funzioni get e set generate internamente. Se la tua proprietà di navigazione getter / setter lavora per te nel tuo utilizzo di Entity Framework, prova a rivederli solo alle proprietà, ricompilare e vedere se Entity Framework è ancora in grado di funzionare correttamente:

  public virtual ICollection RSVPs; 

La parola chiave virtual in C # consente di sovrascrivere un metodo o una proprietà da classi figlio. Per ulteriori informazioni, consultare la documentazione MSDN sulla parola chiave “virtuale”

AGGIORNAMENTO: È evidente che la mia risposta non è allineata a quella che ci si aspettava date le circostanze della domanda, ma la lascerò qui per chiunque cerchi una risposta semplice alla domanda originale non descrittiva.

Capisco la frustrazione dell’OP, questo uso del virtuale non è per l’astrazione basata su modelli a cui è efficace il modificatore virtuale defacto.

Se qualcuno ancora sta lottando con questo, vorrei offrire il mio punto di vista, mentre cerco di mantenere le soluzioni semplici e il gergo al minimo:

Entity Framework in un pezzo semplice utilizza il caricamento lazy, che equivale a preparare qualcosa per un’esecuzione futura. Questo si adatta al modificatore “virtuale”, ma c’è di più in questo.

In Entity Framework, l’utilizzo di una proprietà di navigazione virtuale consente di indicarlo come l’equivalente di una chiave esterna nullable in SQL. Non devi MAI partecipare a tutte le tabelle con chiave quando esegui una query, ma quando hai bisogno delle informazioni, diventa demand-driven.

Ho anche menzionato nullable perché molte proprietà di navigazione non sono rilevanti all’inizio. Ad esempio, in uno scenario cliente / ordini, non è necessario attendere fino al momento in cui un ordine viene elaborato per creare un cliente. È ansible, ma se si dispone di un processo in più fasi per ottenere ciò, è ansible che sia necessario mantenere i dati del cliente per il completamento successivo o per la distribuzione agli ordini futuri. Se tutte le proprietà del nav sono state implementate, dovresti stabilire ogni chiave esterna e campo relazionale sul salvataggio. Questo semplicemente riporta i dati in memoria, il che sconfigge il ruolo della persistenza.

Quindi, anche se può sembrare criptico nell’esecuzione effettiva in fase di esecuzione, ho trovato che la migliore regola da seguire sarebbe: se si stanno esportando dati (leggendo in un modello di vista o in un modello serializzabile) e hanno bisogno di valori prima dei riferimenti, non usare virtuale; Se il tuo ambito raccoglie dati che potrebbero essere incompleti o la necessità di eseguire ricerche e non richiede che ogni parametro di ricerca sia completato per una ricerca, il codice farà un buon uso del riferimento, in modo simile all’utilizzo delle proprietà del valore nullable int? lungo?. Inoltre, l’astrazione della logica aziendale dalla raccolta dei dati fino al momento in cui è necessario iniettarla presenta molti vantaggi in termini di prestazioni, simili all’istanziazione di un object e all’avvio su null. Entity Framework utilizza molte riflessioni e dinamiche, che possono ridurre le prestazioni e la necessità di disporre di un modello flessibile in grado di scalare la domanda è fondamentale per la gestione delle prestazioni.

Per me, questo ha sempre avuto più senso dell’uso di gergo tecnico sovraccarico come proxy, delegati, gestori e così via. Una volta che hai colpito la tua terza o quarta lingua di programmazione, può diventare complicato con questi.

È abbastanza comune definire le proprietà di navigazione in un modello come virtuali. Quando una proprietà di navigazione è definita come virtuale, può sfruttare alcune funzionalità di Entity Framework. Il più comune è il caricamento pigro.

Il caricamento lento è una funzionalità utile di molte ORM perché consente di accedere in modo dinamico ai dati correlati da un modello. Non recupera inutilmente i dati correlati finché non viene effettivamente raggiunto, riducendo così la query anticipata dei dati dal database.

Dal libro “ASP.NET MVC 5 con Bootstrap e Knockout.js”

Nel contesto di EF, contrassegnare una proprietà come virtuale consente a EF di utilizzare il caricamento lazy per caricarlo. Per il caricamento lento a lavorare EF deve creare un object proxy che sostituisce le proprietà virtuali con un’implementazione che carica l’ quadro referenziata al primo accesso. Se non si contrassegna la proprietà come virtuale, il caricamento lento non funzionerà con esso.