A mio parere, la domanda importante è: hai disattivato LazyLoading?
Se non hai fatto nulla, è attivo per impostazione predefinita.
Così quando si esegue Person.Pathway.Country
, si invocherà un'altra chiamata al server di database (a meno che non si stia effettuando un caricamento ansioso, di cui parlerò tra un momento). Dato che stai usando il modello di repository - questo è un grande no-no. I controllori non dovrebbero causare chiamate dirette al server del database.
Una volta C ontroller ha ricevuto le informazioni dal M odello, dovrebbe essere pronto a proiezione (se necessario), e passare al V ista, non va indietro al M odel.
questo nella nostra implementazione (usiamo anche repository, EF4, e unità di lavoro), si disattiviamo caricamento pigro, e consentire il passaggio attraverso le proprietà di navigazione attraverso il nostro livello di servizio (una serie di "Include "affermazioni rese più dolci da enumerazioni e metodi di estensione".
Abbiamo quindi carico intermittente queste proprietà come richiedono i Controller. Ma la cosa importante è, , il controller deve richiederli esplicitamente.
Che fondamentalmente dice all'interfaccia utente: "Ehi, stai solo ottenendo le informazioni principali su questa entità. Se vuoi qualcos'altro, chiedilo".
abbiamo anche una servizio di livello mediazione tra il controller e il repository (repository nostri tornare IQueryable<T>
). Ciò consente al repository di uscire dal business della gestione di associazioni complesse. Il carico impaziente viene eseguito a livello di servizio (oltre a cose come il paging).
Il vantaggio del livello di servizio è semplice: accoppiamento più lento. Il repository gestisce solo Aggiungi, Rimuovi, Trova (che restituisce IQueryable), Unità di lavoro gestisce "newing" di DC e Commiting delle modifiche, il livello di servizio gestisce la materializzazione delle entità in raccolte concrete.
E 'una bella, approccio 1-1 stack simile:
personService.FindSingle(1, "Addresses") // Controller calls service
|
--- Person FindSingle(int id, string[] includes) // Service Interface
|
--- return personRepository.Find().WithIncludes(includes).WithId(id); // Service calls Repository, adds on "filter" extension methods
|
--- IQueryable<T> Find() // Repository
|
-- return db.Persons; // return's IQueryable of Persons (deferred exec)
Non abbiamo fino allo strato di MVC ancora (che stiamo facendo TDD), ma un livello di servizio potrebbe essere un altro luogo è possibile idrate le entità principali in ViewModels. E ancora: spetterebbe al controllore decidere quante informazioni desidera.
Ancora una volta, si tratta di un accoppiamento libero. I controller devono essere il più semplici possibile e non devono preoccuparsi di associazioni complesse.
In termini di quanti repository, questo è un argomento molto discusso. Ad alcuni piace averne uno per entità (overkill se me lo chiedi), alcuni preferiscono un gruppo basato sulla funzionalità (ha senso in termini di funzionalità, più facile da usare), tuttavia ne abbiamo uno per radice aggregata.
Posso solo immaginare sul tuo modello che "Persona" dovrebbe essere l'unica radice aggregata che posso vedere.
Pertanto, non ha molto senso avere un altro repository per gestire "Percorsi", quando un percorso è sempre associato a una particolare "Persona". Il repository Person dovrebbe gestirlo.
Ancora: forse se si esegue lo screen-screen dell'EDMX, potremmo darvi ulteriori suggerimenti.
Questa risposta potrebbe estendersi un po 'troppo in base alla portata della domanda, ma ho pensato di dare una risposta approfondita, poiché ora stiamo affrontando questo scenario esatto.
HTH.
Grazie, la tua risposta ha sicuramente chiarito il mio pensiero. Le risposte finora mi hanno aiutato a capire quando guardo il mio codice sono preoccupato per ciò che EF sta facendo dietro le quinte per realizzare questi oggetti grafici. So che posso far girare SQL Profiler per vedere cosa sta succedendo, ma il mio pensiero iniziale è che l'astrazione di questo fuori dal controller mi darà un controllo migliore in futuro se le prestazioni o l'obbligo di fornire questi dati a fonti remote diventino un requisito. Il tuo suggerimento di un livello di servizio tra controller e repository è qualcosa che esaminerò. –
@Daz Lewis - sicuramente. Abbiamo un'API per il nostro sito web. Questo è il motivo per cui abbiamo il livello di servizio. Sia il nostro sito Web che l'API sono "clienti". Ciò consente un modello di programmazione piacevole, scorrevole (ma stretto).BTW - NON DEVI usare SQL Profiler. Esiste un metodo su ObjectQuery chiamato .ToTraceString. Usiamo questo con la registrazione, tutti i nostri metodi di repository eseguono il debug di questa riga (livello di informazioni), in modo che possiamo vedere cosa viene eseguito. Ad ogni modo, guarda nel livello di servizio. I nostri repository sono molto semplici - date un'occhiata ad alcune delle mie domande per vedere come l'ho fatto. – RPM1984
"I controller non devono causare chiamate dirette al server database", quindi il controller non dovrebbe chiamare un repository per causare chiamate dirette al server database. Quando si accede a una proprietà che verrà caricata come pigra, non si verificherà una chiamata diretta al server di database nello stesso modo in cui il repository sta causando una chiamata diretta al server di database. Sì, è sicuro che causi una chiamata al server del database, ma indirettamente attraverso l'infrastruttura utilizzando uno strumento ORM. – adriaanp