2013-02-10 8 views
5

Ich habe ein Problem mit ValueInjecter, um tiefe Klone von EntityFramework POCOs in ähnliche DTO-Klassen zu erstellen. Wenn ich von einem komplizierten POCO-Objekt mit mehreren verbundenen Entitäten/untergeordneten Entitäten mit Navigationseigenschaften in ein etwas einfacheres DTO injiziere, scheint ValueInjecter immer noch mehrere Eigenschaftswerte zu berühren und ein langsames Laden dieser Daten aus der Datenbank auszulösen .Verwenden Sie ValueInjecter, um ein EntityFramework POCO in ein DTO zu kopieren, ohne faule Lastenlisten und Eigenschaften auszulösen

Ich glaube, dass ValueInjecter den Wert jeder Eigenschaft in einem bestimmten Quellobjekt abruft, während es sich darauf vorbereitet, die Werte in das angegebene Ziel zu injizieren.

Mein aktuelles Projekt ist ziemlich kompliziert, aber als Beispiel habe ich das NerdDinner Beispiel genommen und replizierte das Problem in einer viel einfacheren Art und Weise. (NerdDinner ist ein Beispiel für Code erster Entwickler mit EF4 (ScottGu NerdDinner Example)

So habe ich die beiden Modellklassen

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

und

public class RSVP 
{ 
    public int RsvpID { get; set; } 
    public int DinnerID { get; set; } 
    public string AttendeeEmail { get; set; } 
    public virtual Dinner Dinner { get; set; } 
} 

ich auch eine DTO-Klasse erstellt..:

public class DinnerDTO 
{ 
    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; } 
} 

Hinweis, dass ich die Rsvps-Sammlung nicht in Dinner in meinem DinnerDTO gefunden habe.

Auch von Bedeutung, verwende ich die CloneInjection-Konvention zum tiefen Klonen eines Objekts. Dieser Code wird sowohl hier auf SO als auch auf vielen anderen Sites als ein Ansatz zur Durchführung einer tiefen Kloninjektion vorgeschlagen. Dieser Code gefunden wird: CloneInjection Code

Nun, die träges Laden auftretenden zu betonen, ich ging und eingefügt mit der Id für ein Abendessen 10.000 RSVP = 1.

ich dann den folgenden Code ausführen:

var dinner = nerdDinners.Dinners.Where(x => x.DinnerId == 1).FirstOrDefault(); 
DinnerDTO dinnerDTO = new DinnerDTO(); 
dinnerDTO.InjectFrom<CloneInjection>(dinner); 

Wenn ich einen Haltepunkt an der Linie mit dem InjectFrom setzen und darüber hinwegtrete, gibt es eine erhebliche Verzögerung, da es die 10.000 RSVPs faul lädt. Wenn ich auch einen Haltepunkt im CloneInjection-Code sowohl bei den Methoden Match als auch SetValue einstelle, wird keiner von beiden so lange gedrückt, bis sich die Ladeverzögerung aufgelöst hat. Dies sagt mir, dass es etwas sein muss, das ValueInjecter intern ist, das die verzögerte Last der RSVPs Eigenschaft verursacht.

Nun, wenn ich den obigen Code zu diesem ändern: (Hinzufügen eines Include auf die Abfrage)

var dinner = nerdDinners.Dinners.Where(x => x.DinnerId == 1).Include("RSVPs").FirstOrDefault(); 
DinnerDTO dinnerDTO = new DinnerDTO(); 
dinnerDTO.InjectFrom<CloneInjection>(dinner); 

Diese Änderung erzwingt eine „Eager Load“ aus der Liste der RSVP, und wie erwartet, die Verzögerung ist in der Zeile mit der Abfrage, und die InjectFrom Zeile tickt vorbei ohne Verzögerung überhaupt.

Ich habe einige vage verwandte Beiträge zu StackOverflow gelesen, einige empfehlen, das LazyLoading auf dem Datenkontext zu deaktivieren und dann zu aktivieren. Ich habe es versucht, und obwohl es funktioniert hat, fühlte es sich ziemlich dreckig an.

Ich las diesen Beitrag (Copying NHibernate POCO to DTO without triggering lazy load or eager load) und den zugehörigen Code, sein Ansatz scheint einige NHibernate-Methoden zu verwenden, um festzustellen, ob eine Eigenschaft ein nicht initialisierter Proxy ist und sie irgendwie ausstreichen. Ich konnte nichts Ähnliches in EF4 finden.

Der Teil von dem, der mich wirklich stolpert, ist, dass die Rsvps-Sammlung nicht einmal in meinem DTO-Objekt ist, ich bin nicht einmal daran interessiert, dass es Wert ist. Das scheint mir nicht richtig zu sein. Ich denke nicht, dass der ValueInjecter-Code Werte von Eigenschaften abfragen sollte, die das Zielobjekt möglicherweise nicht interessieren würde.

Gibt es einige Mittel, mit denen ich dieses Verhalten in ValueInjecter überschreiben kann? Irgendwie verzögern Bewertung der Eigenschaften Werte, bis es absolut sicher ist, ich möchte den Wert, wie in der SetValue Methode der ConventionInjection? Dann würde es zumindest keine Eigenschaften auswerten, die mein DTO nicht einmal will. Die beste Lösung, die ich mir vorstellen kann, wäre, dass ValueInjecter oder eine benutzerdefinierte Konvention irgendwie in der Lage ist, eine entladene Lazy Load-Eigenschaft zu erkennen, und anstatt sie zu bewerten, würde sie stattdessen diese Eigenschaft auf null setzen das Ziel. Ich denke nicht, dass das möglich ist.

Gibt es einen besseren Ansatz durch EF, den ich verwenden sollte? Ich möchte nicht alles in die Datenbank laden.

Bin ich komplett ausgeschaltet, und das Problem ist überhaupt nicht in ValueInjecter?

* EDIT * Ich habe eine Lösung gefunden und beantwortet diese Frage, ich bin immer noch neugierig, wenn ich es falsch, nur mache, oder wenn es ein noch besserer Ansatz ist.

Antwort

5

Ich habe das Gefühl, dass ich eine befriedigende Antwort auf meine eigene Frage gefunden habe, und so werde ich das selbst abschließen. Ich endete zwei Dinge zu tun.

Zuerst habe ich Lazy Loading vollständig auf dem dbContext deaktiviert. Etwas ähnliches im dbContext-Konstruktor.

this.Configuration.LazyLoadingEnabled = false;

Ich war nicht wirklich die faul Last-Funktion von EF verwenden, ist es so ausschalten kein großer Verlust war. Das bedeutet nur, dass wenn ich möchte, dass verwandte Entitäten gefüllt werden, ich sie in einer Include für meine Abfrage angeben muss. Keine große Sache.

Die andere Sache, die ich tat, war die tiefe Klon Injektion Konvention zu überarbeiten, um den SmartConventionInjection Code hier SmartConventionInjection source zu finden. Abgesehen davon, dass es eine noch schnellere Injektion als die Basisinjektion ist, berührt es auch keine Eigenschaftswerte bis zum Aufruf SetValue, so dass selbst wenn ich einige träge Ladeeigenschaften hätte, diese nicht berührt würden, außer der DTO hätte diese Eigenschaft ebenfalls.

+3

ich könnte dich jetzt küssen! (auf eine freundliche, nicht bedrohliche Art und Weise) –

Verwandte Themen