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.
Potrei baciarti adesso! (in modo amichevole e non minaccioso) –