2013-04-17 10 views
18

Die meisten (wenn nicht alle) Entity Framework POCOs haben virtuelle Funktionen. Ich brauche diese Funktionen, um virtuell zu sein, damit die Entitäten faul geladen werden können.Wie vermeidet man den Aufruf der virtuellen Funktion im Konstruktor?

Wenn ich Accommodations im Konstruktor initialisiere, werde ich eine virtuelle Funktion im Konstruktor aufrufen, was eine schlechte Übung ist.

Aber wie kann ich Accommodations initialisieren, wenn nicht im Konstruktor?

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

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

der Punkt des träges Ladens ist _nicht_ es überhaupt zu initialisieren, bis erste Benutzung. –

+0

@JohnWillemse Wenn ich es null lasse, bekomme ich null Ausnahme aus meiner Sicht. –

+0

Nein, Sie testen auf Null und initialisieren es bei Bedarf. Siehe Willem Duncans Antwort unten für eine Demonstration der Verwendung. Vielleicht verwechseln wir hier verschiedene Muster, wie Daniels Kommentar zu derselben Antwort sagt. –

Antwort

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

    public Venue() { } 

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

Was seltsame Namenskonvention ist das? Normalerweise setzen Sie den Unterstrich vor. –

+1

@DanielHilgarth, ich würde es überhaupt keine Convention nennen - nur eine (wahrscheinlich schlechte) Gewohnheit von mir, die ich wirklich ändern muss;) –

+0

EF mag keine führenden Unterstreichungen. – Casey

2

Mit verzögertes Laden, Sie initialisieren nicht einmal die Accommodations bis es zuerst zugegriffen wird, so ist es null verlassen.

Sie wickeln kann, wie es automatisch initialisiert sich zu machen folgt:

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

Seien Sie sicher, den Kommentar unten zu dieser Lösung zu lesen!

+7

Er spricht über Lazy Loading im Kontext eines ORM. Das ORM kümmert sich um all das für Sie, Ihre Antwort verfehlt den Punkt. Siehe auch [diese Antwort] (http://stackoverflow.com/questions/14774008/good-or-bad-practice-initializing-objects-in-getter/14774042#14774042) in Bezug auf die Praxis, die Sie hier zeigen. –

+0

Guter Punkt, lerne jeden Tag etwas, habe einen Zeiger auf die Antwort hinzugefügt. –

+0

Danke für den Link Daniel. –

14

Eine andere Möglichkeit ist, den Setter als privat zu markieren. Dies wird das Problem des Aufrufs virtueller Member im Konstruktor beseitigen.

Sobald Sie dies getan haben, müssen Sie Anrufern (außer EF) die Möglichkeit geben, diese Eigenschaft nach Bedarf für Ihr Design festzulegen. Sie können einen überladenen Konstruktor verwenden, um eine Liste von Unterkünften zu übergeben, oder optional Ihre Sammlung kapseln (domänengesteuertes Design) und Methoden zum Hinzufügen/Entfernen von Elementen verwenden (beachten Sie, dass EF zu "hackisch" wird, da es keine Unterstützung für vollständig gekapselt hat) Sammlungen, anders als mit 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

Genau das, was ich brauchte. Lustig, wie diese Frage über ein Jahr alt ist, und doch postest du diese Antwort nur 4 Stunden bevor ich danach suche! – Xcelled194

0

mit der C# 6.0 Standardinitialisierung es ohne die Verwendung von privaten Variablen vereinfacht werden könnte:

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