2009-02-07 6 views
14

Ich habe zahlreiche Beispiele von Lazy Loading gesehen - was ist Ihre Wahl?Lazy Loading - was ist der beste Ansatz?

eine Modellklasse zum Beispiel Gegeben:

public class Person 
{ 
    private IList<Child> _children; 
    public IList<Child> Children 
    { 
     get { 
      if (_children == null) 
       LoadChildren(); 
      return _children; 
     } 
    } 
} 

Die Klasse Person nichts wissen sollte, wie es Kinder geladen werden .... oder sollte es? Sicher sollte es kontrollieren, wenn Eigenschaften bevölkert werden oder nicht?

Würden Sie ein Repository verwenden, das eine Person mit ihrer Children-Sammlung koppelt, oder verwenden Sie einen anderen Ansatz, z. B. eine lazyload-Klasse - selbst dann möchte ich keine Lazyload-Klassenverwischung in meiner Modellarchitektur.

Wie würden Sie mit der Leistung umgehen, wenn Sie zuerst eine Person und dann ihre Children (d. H. Nicht lazy laden in diesem Fall) oder irgendwie faul laden.

Fällt alles auf persönliche Entscheidung hinaus?

+0

Problem - das ist oft ein gutes Beispiel für lokale Optimierung auf Kosten der globalen Optimierung. – dkretz

Antwort

14

Die beste Lazy Loading ist es zu vermeiden;) Thread Sicherheit ist ein unmittelbares Problem, das Sie behandeln müssen. Ich habe keine Zählung, wie oft ich Produktionssysteme mit 8 CPU-Kernen laufen gesehen habe Lazy Loading 8 Mal für jedes einzelne Lazy Loading Pattern im Einsatz. Zumindest bei Server-Startups neigen alle Server-Cores dazu, an denselben Orten zu landen.

Lassen Sie ein DI-Framework es für Sie stattdessen konstruieren, wenn Sie können. Und wenn Sie nicht können, bevorzuge ich immer noch explizite Konstruktion. Also alle Arten von AOP Magie einfach nicht mit mir schneiden, gehen Sie für explizite Konstruktion außerhalb der Klasse. Platziere es nicht in der Personenklasse, sondern mache einfach einen Dienst, der die Objekte in der richtigen Weise konstruiert.

Einführung "magische" Schichten, die mehr oder weniger transparent diese Dinge tun scheinen wie eine nette Idee, aber ich habe noch zu Implementierungen, die nicht unvorhergesehene und problematische Folgen haben.

+0

Vielen Dank für Ihre Zeit, können Sie ein DI-Framework und explizite Konstruktion verwenden? –

+0

Ich glaube, er sagte, dass die Person-Klasse explizit die Kinder (mit LoadChildren() vermutlich) während seiner eigenen Initialisierung erstellen lässt keinen Zweifel über den Zustand von _Kinder. Und Dependency Injection, nun, da gibt es viele Fäden hier, die besser sind als ich in einem Kommentar. – JMD

+0

Auch - Sie verlieren die Atomizität der Abfrage. Und meistens ist es die effizienteste Gesamtstrategie, eine einzige Abfrage mit (äußeren?) Joins für die untergeordneten Datensätze zu erstellen und alles in einer Transaktion zu erhalten, anstatt sie über mehrere Datenbankuntertreffer hinweg zu verteilen. – dkretz

0

Ich denke, das ist genau die Art von Problem, das am besten von AOP behandelt wird (z. B. PostSharp). Haben Sie Ihre Lazy Loading als ein Aspekt und dann verwenden Sie es, um jede Eigenschaft dekorieren, die Sie träge geladen werden wollen. Haftungsausschluss: habe es nicht versucht; nur daran gedacht, dass es sollte funktionieren.

1

sprach ich über eine Lösung, die ich here

+0

Danke für Ihre Zeit, ist das nicht nur eine andere Abhängigkeit obwohl? Ich bin jedoch an der Vorgehensweise interessiert. –

1

Sie können das Muster Virtual Proxy zusammen mit dem Observer pattern verwenden. Dies würde Ihnen ein träges Laden ermöglichen, ohne dass die Person-Klasse explizites Wissen darüber hat, wie Kinder geladen werden.

0

Ich fragte nur eine verwandte Frage here, aber es war schwerer auf der Unveränderlichkeit & Thread Safety Tack. Viele gute Antworten und Kommentare. Sie können es nützlich finden.

0

Hier ist ein Beispiel verzögertes Laden der Umsetzung der Muster Proxy mit

Die Person-Klasse, die mit dem Rest Ihrer Modelle leben. Kinder werden als virtuell markiert, sodass sie in der PersonProxy-Klasse überschrieben werden können.

public class Person { 
    public int Id; 
    public virtual IList<Child> Children { get; set; } 
} 

Die PersonRepository-Klasse, die mit dem Rest Ihrer Repositorys zusammenleben würde. Ich habe die Methode eingeschlossen, um die Kinder in dieser Klasse zu bekommen, aber Sie könnten sie in einer ChildRepository-Klasse haben, wenn Sie das wollten.

public class PersonRepository { 
    public Person FindById(int id) { 
     // Notice we are creating PersonProxy and not Person 
     Person person = new PersonProxy(); 

     // Set person properties based on data from the database 

     return person; 
    } 

    public IList<Child> GetChildrenForPerson(int personId) { 
     // Return your list of children from the database 
    } 
} 

Die PersonProxy-Klasse, die mit Ihren Repositorys lebt. Dies erbt von Person und führt das verzögerte Laden aus. Sie können auch einen booleschen Wert verwenden, um zu überprüfen, ob dieser bereits geladen wurde, anstatt zu überprüfen, ob Children == null ist.

public class PersonProxy : Person { 
    private PersonRepository _personRepository = new PersonRepository(); 

    public override IList<Child> Children { 
     get { 
      if (base.Children == null) 
       base.Children = _personRepository.GetChildrenForPerson(this.Id); 

      return base.Children; 
     } 
     set { base.Children = value; } 
    } 
} 

könnten Sie es verwenden, wie so

Person person = new PersonRepository().FindById(1); 
Console.WriteLine(person.Children.Count); 

Natürlich könnten Sie PersonProxy zum PersonRepository in einer Schnittstelle nehmen und sie alle über einen Dienst zugreifen, wenn Sie die PersonRepository nicht nennen wollen direkt.