2013-04-17 13 views
18

La maggior parte (se non tutti) i miei POCO di Entity Framework hanno funzioni virtuali. Ho bisogno che queste funzioni siano virtuali in modo che le entità possano essere caricate in modo pigro.Come evitare di chiamare la funzione virtuale nel costruttore?

Se inizializzo Accommodations nel costruttore, chiamerò una funzione virtuale nel costruttore, che è una cattiva pratica.

Ma come posso inizializzare Accommodations se non nel costruttore?

public class Venue 
{ 
    public Venue() 
    { 
     Accommodations = new HashSet<Accommodation>(); 
    } 

    public virtual ICollection<Accommodation> Accommodations { get; set; } 
} 
+1

il punto di caricamento pigro è _non_ inizializzare affatto, fino primo utilizzo. –

+0

@JohnWillemse Se lo lascio null, otterrò un'eccezione null nella mia vista. –

+0

No, si prova per null e lo si inizializza quando necessario. Vedi la risposta di Willem Duncan sotto per una dimostrazione dell'uso. Forse stiamo confondendo schemi diversi qui, come nel commento di Daniel sulla stessa risposta. –

risposta

12
public class Venue 
{ 
    private accommodations_ = new HashSet<Accommodation>(); 

    public Venue() { } 

    public virtual ICollection<Accommodation> Accommodations 
    { 
     get { return accommodations_; } 
     set { accommodations_ = value; } 
    } 
} 
+3

Che strana convenzione di denominazione è quella? Di solito metti il ​​segno di sottolineatura davanti. –

+1

@DanielHilgarth, io non lo chiamerei un convegno a tutti - solo una (probabilmente cattiva) abitudine di mio che ho davvero bisogno di cambiare;) –

+0

EF non si tanto come leader di sottolineatura in ogni caso. – Casey

2

Con caricamento pigro, non si nemmeno inizializzare il Accommodations fino a che non è primo accesso, in modo da lasciarlo null.

Puoi avvolgere come segue per renderlo automaticly inizializzare stesso:

private ICollection<Accommodation> _accommodations; 

public virtual ICollection<Accommodation> Accommodations { 
    get { 
     if (_accommodations == null) 
     { 
      // Initialize or load data here. 
      _accommodations = new HashSet<Accommodation>(); 
     } 
     return _accomodations; 
    } 
    set { 
     _accommodations = value; 
    } 
} 

Assicurarsi di leggere il commento qui sotto riguardo a questa soluzione!

+7

Sta parlando di caricamento pigro nel contesto di un ORM. L'ORM si prende cura di tutto questo per te, quindi la tua risposta non coglie il punto. Inoltre, si prega di consultare [questa risposta] (http://stackoverflow.com/questions/14774008/good-or-bad-practice-initializing-objects-in-getter/14774042#14774042) per quanto riguarda la pratica si mostra qui. –

+0

Buon punto, impara qualcosa ogni giorno, hai aggiunto un puntatore alla risposta. –

+0

Grazie per il link Daniel. –

14

Un'altra opzione è contrassegnare il setter come privato. Questo eliminerà il problema di chiamare membri virtuali nel costruttore.

Una volta fatto questo, è necessario fornire modi per i chiamanti (diversi EF) per impostare la proprietà necessarie per il proprio disegno. È possibile utilizzare un costruttore di overload per passare in un elenco di strutture ricettive, o, in alternativa incapsulare la vostra collezione (design driven dominio) e utilizzare metodi per aggiungere/rimuovere elementi (nota, con EF questo diventa "hacker", in quanto manca il supporto per completamente incapsulato collezioni, a differenza con NHibernate):

public class Venue 
{ 
    public Venue() 
    { 
     Accommodations = new HashSet<Accommodation>(); 
    } 

    public Venue(ICollection<Accommodation> accommodations) 
    { 
     Accommodations = new List<Accommodation>(accommodations); 
    } 

    public virtual ICollection<Accommodation> Accommodations { get; private set; } 
} 
+2

Esattamente quello di cui avevo bisogno. Strano come questa domanda abbia più di un anno, eppure tu mandi questa risposta solo 4 ore prima di andare a cercarla! – Xcelled194

0

con l'inizializzazione di default C# 6.0 potrebbe essere semplificato senza l'uso di variabili private:

public class Venue 
{ 
    public virtual ICollection<Accommodation> Accommodations {get; set; } = new HashSet<Accommodation>(); 
} 
Problemi correlati