2013-02-10 9 views
5

Mam problem z użyciem ValueInjecter do tworzenia głębokich klonów EntityFramework POCO do podobnych klas DTO.Użyj ValueInjecter, aby skopiować POCO EntityFo do DTO bez wywoływania leniwych list ładunków i właściwości

W przypadkach, w których wstrzykiwam ze skomplikowanego obiektu POCO z wieloma obiektami powiązanymi/obiektami podrzędnymi z właściwościami nawigacji do nieco prostszego DTO, ValueInjecter wydaje się nadal dotykać wielu wartości właściwości i ponoszenia leniwego ładowania tych danych z bazy danych .

Wierzę, że to ValueInjecter pobiera wartość każdej właściwości w konkretnym obiekcie źródłowym, przygotowując się do wprowadzenia wartości do określonego celu.

Mój rzeczywisty projekt jest dość skomplikowany, ale jako przykład wziąłem przykład NerdDinner i zreplikowałem sprawę w znacznie prostszy sposób. (NerdDinner jest przykładem kodu pierwszym dev z EF4 (ScottGu NerdDinner Example)

Więc mam dwie klasy modelu

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

i

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

ja też stworzył klasę DTO..:

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

Uwaga, dla której nie ma kolekcji Rsvps znalezionej w Dinner w mojej DinnerDTO.

Co ważne, używam konwencji CloneInjection do głębokiego klonowania obiektu. Kod ten jest zasugerowany zarówno tutaj, na SO, jak i wielu innych stronach, jako podejście do wykonywania głębokiego zastrzyku klonu. Kod ten znajduje się tutaj: CloneInjection Code

Teraz, aby podkreślić leniwego ładowania zachodzącą, poszedłem i włożona 10000 RSVP za obiad z id = 1.

I następnie wykonać następujący kod:

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

Jeśli ustawię punkt przerwania na linii z InjectFrom, i przekroczę go, istnieje znaczne opóźnienie, ponieważ leniwy ładuje 10.000 RSVP w górę. Jeśli ustawię również punkt przerwania w kodzie klonowania zarówno metodami Match, jak i SetValue, żadne z nich nie zostaną trafione do momentu rozwiązania opóźnienia ładowania. To mówi mi, że musi to być coś wewnętrznego dla ValueInjecter, który ponosi leniwy ładunek z właściwości RSVPs.

Teraz, jeśli mogę zmodyfikować powyższy kod do tego: (dodanie Include do zapytania)

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

Ta zmiana wymusza „Eager Load” na liście RSVP, a zgodnie z oczekiwaniami, LGD w wierszu z zapytaniem, a linia InjectFrom przechodzi w przeszłość bez żadnego opóźnienia.

Przeczytałem kilka niejasno pokrewnych postów na StackOverflow, kilka polecam wyłączenie, a następnie włączenie LazyLoading na datacontext. Próbowałem tego i choć działało, było dość brudno.

Przeczytałem ten post (Copying NHibernate POCO to DTO without triggering lazy load or eager load) i związany z nim kod, jego podejście wydaje się być za pomocą niektórych metod NHibernate w celu określenia, czy właściwość jest niezainicjowanym proxy i jakoś je usunąć. Nie udało mi się znaleźć niczego podobnego w EF4.

Częścią tego, co naprawdę mnie niepokoi, jest to, że kolekcja Rsvps nie jest nawet w moim obiekcie DTO, nie jestem nawet zainteresowany jej wartością. Nie wydaje mi się to właściwe. Nie sądzę, że kod ValueInjecter powinien sprawdzać wartości właściwości, których obiekt docelowy może nawet nie obchodzić.

Czy istnieją jakieś sposoby, dzięki którym można zastąpić to zachowanie w ValueInjecter? W jakiś sposób odroczyć ocenę wartości właściwości, dopóki nie jest absolutnie pewne, że chcę wartość, na przykład w metodzie SetValue z ConventionInjection? Wtedy przynajmniej nie byłoby oceny właściwości, których moje DTO nawet nie chce.

Najlepszym rozwiązaniem, jakie przychodzi mi na myśl, byłoby dla ValueInjecter lub niestandardowej konwencji, aby w jakiś sposób móc wykryć niezaładowaną właściwość leniwego obciążenia, a zamiast jej oceny, po prostu ustawiłaby tę właściwość na wartość null cel. Nie sądzę, że jest to możliwe.

Czy istnieje jakieś lepsze podejście z EF, którego powinienem używać? Nie chcę chętni Załaduj wszystko do bazy danych.

Czy całkowicie jestem wyłączony, a problem w ogóle nie występuje w ValueInjecterze?

* EDIT * znalazłem rozwiązanie i odpowiedział na to pytanie, wciąż jestem ciekaw, czy jestem po prostu robi to źle, czy jest tam jeszcze lepszym rozwiązaniem.

Odpowiedz

5

Czuję, że znalazłem satysfakcjonującą odpowiedź na moje własne pytanie, więc zamierzam to sam zamknąć. Skończyło się na zrobieniu dwóch rzeczy.

Najpierw wyłączyłem Lazy Loading całkowicie na dbContext. Coś podobnego do tego w konstruktorze dbContext.

this.Configuration.LazyLoadingEnabled = false;

byłem naprawdę nie używając leniwy funkcji obciążenia EF, więc wyłączając go nie było duże straty. Oznacza to po prostu, że jeśli chcę, aby obiekty powiązane były wypełnione, muszę je określić w zapytaniu Include. Nie ma sprawy.

Inną rzeczą, którą zrobiłem, było przerobienie konwencji dotyczącej głębokiego zastrzyku klonów, aby użyć kodu SmartConventionInjection, który został znaleziony tutaj SmartConventionInjection source. Poza tym, że jest to jeszcze szybsza iniekcja niż wtrysk podstawowy, nie dotyka również wartości właściwości do czasu wywołania SetValue, więc nawet jeśli miałbym pewne leniwe właściwości ładowania, nie byłyby dotykane, gdyby DTO również nie posiadało tej właściwości.

+3

Mogę Cię pocałować już teraz! (w przyjazny, nie zagrażający sposób) –

Powiązane problemy