2013-02-10 5 views
5

Ho riscontrato un problema con l'utilizzo di ValueInjecter per creare cloni profondi di EntityFramework POCO in classi DTO simili.Utilizzare ValueInjecter per copiare un POCO EntityFramework su un DTO senza attivare lazy load list e proprietà

Nei casi in cui sto effettuando l'iniezione da un oggetto POCO complicato con più entità correlate/entità figlio con proprietà di navigazione in un DTO un po 'più semplice, ValueInjecter sembra ancora toccare più valori di proprietà e incorrere nel caricamento lento di questi dati dal database .

Credo che sia ValueInjecter che ottiene il valore di ogni proprietà in un particolare oggetto di origine mentre si prepara a iniettare i valori nella destinazione specificata.

Il mio progetto attuale è abbastanza complicato, ma ad esempio, ho preso l'esempio di NerdDinner e ho replicato il problema in un modo molto più semplice. (NerdDinner è un esempio di codice di primo dev con EF4 (ScottGu NerdDinner Example)

Così ho le due classi del modello

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

e

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

Ho anche creato una classe 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; } 
} 

Nota che non ho la collezione Rsvps trovata in Dinner nel mio DinnerDTO.

Anche di importanza, sto usando la convenzione CloneInjection per la clonazione profonda di un oggetto. Questo codice è suggerito sia qui su SO, sia su molti altri siti come approccio per eseguire un'iniezione profonda di cloni. Questo codice si trova qui: CloneInjection Code

Ora, per sottolineare il carico si verificano pigro, sono andato e inserito 10.000 RSVP di una cena con Id = 1.

ho quindi eseguire il codice seguente:

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

Se si imposta un punto di interruzione sulla linea con lo InjectFrom e lo si passa sopra, c'è un ritardo considerevole in quanto il carico pigro aumenta di 10.000 RSVP. Se si imposta anche un punto di interruzione nel codice CloneInjection in entrambi i metodi Match e SetValue, nessuno di questi viene colpito fino a dopo la risoluzione del lag di caricamento. Questo mi dice che deve essere qualcosa di interno a ValueInjecter che sta causando il carico lento della proprietà RSVPs.

Ora, se modifico il codice qui sopra per questo: (aggiunta di un Include alla query)

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

Questo cambiamento impone un "Load desideroso" della lista del RSVP, e come previsto, il ritardo è in linea con la query, e la riga InjectFrom passa oltre senza alcun ritardo.

Ho letto alcuni post vagamente correlati su StackOverflow, alcuni consigliano di disabilitare e abilitare LazyLoading sul datacontext. Ci ho provato, e mentre funzionava, mi sentivo piuttosto sporco.

Ho letto questo post (Copying NHibernate POCO to DTO without triggering lazy load or eager load) e il relativo codice, il suo approccio sembra utilizzare alcuni metodi di NHibernate per determinare se una proprietà è un proxy non inizializzato e in qualche modo eliminarli. Non sono riuscito a trovare nulla di simile in EF4.

La parte di questo che mi fa davvero impazzire, è che la raccolta Rsvps non è nemmeno nel mio oggetto DTO, non mi interessa nemmeno il suo valore. Questo non mi sembra giusto. Non penso che il codice ValueInjecter debba interrogare i valori delle proprietà a cui l'oggetto target potrebbe non interessare.

Esistono alcuni modi con cui è possibile ignorare questo comportamento in ValueInjecter? In qualche modo rinvia la valutazione dei valori delle proprietà finché non è assolutamente certo che voglio il valore, ad esempio nel metodo SetValue di ConventionInjection? Quindi almeno non valuterebbe le proprietà che il mio DTO non vuole nemmeno.

La soluzione migliore che riesco a pensare, sarebbe per ValueInjecter, o una convenzione personalizzata, in qualche modo essere in grado di rilevare una proprietà di carico pigro non scaricato, e invece di valutarla, dovrebbe invece semplicemente impostare quella proprietà su null su il bersaglio. Non penso che sia possibile però.

C'è un approccio migliore tramite EF che dovrei usare? Non voglio desiderare di caricare tutto nel database.

Sono completamente spento e il problema non si trova in ValueInjecter?

* EDIT * Ho trovato una soluzione e risposto a questa domanda, io sono ancora curioso di sapere se sto solo facendo male, o se v'è un approccio ancora migliore.

risposta

5

Mi sento come se avessi trovato una risposta soddisfacente alla mia domanda, e quindi lo chiuderò da solo. Ho finito per fare due cose.

Innanzitutto ho disabilitato Lazy Loading interamente su dbContext. Qualcosa di simile a questo nel costruttore dbContext.

this.Configuration.LazyLoadingEnabled = false;

non ero molto usare la funzione di carico pigro di EF, in modo da spegnerlo era grande perdita. Questo significa solo che se voglio che le entità correlate siano popolate, devo specificarle in un Include sulla mia query. Nessun grosso problema.

L'altra cosa che ho fatto è stata rielaborare la convenzione di iniezione di clone in profondità per utilizzare il codice trovato qui SmartConventionInjection source. Oltre ad essere un'iniezione ancora più veloce dell'iniezione base, non tocca i valori delle proprietà fino alla chiamata SetValue, quindi, anche se avessi alcune proprietà di caricamento lazy, non verrebbero toccati a meno che il DTO avesse questa proprietà.

+3

Potrei baciarti adesso! (in modo amichevole e non minaccioso) –