2010-10-13 18 views
11

Abbiamo un sito MVC di ASP.NET che utilizza le astrazioni di Entity Framework con i modelli Repository e UnitOfWork. Quello che mi chiedo è come altri abbiano implementato la navigazione di complessi oggetti grafici con questi schemi. Vi faccio un esempio da uno dei nostri controllori:Schema per il recupero di grafici di oggetti complessi con pattern di repository con Entity Framework

var model = new EligibilityViewModel 
    { 
     Country = person.Pathway.Country.Name, 
     Pathway = person.Pathway.Name, 
     Answers = person.Answers.ToList(), 
     ScoreResult = new ScoreResult(person.Score.Value), 
     DpaText = person.Pathway.Country.Legal.DPA.Description, 
     DpaQuestions = person.Pathway.Country.Legal.DPA.Questions, 
     Terms = person.Pathway.Country.Legal.Terms, 
     HowHearAboutUsOptions = person.Pathway.Referrers 
    }; 

E 'un processo di registrazione e praticamente tutto appende fuori la persona di classe POCO. In questo caso stiamo memorizzando nella cache la persona attraverso il processo di registrazione. Ora ho iniziato a implementare l'ultima parte del processo di registrazione che richiede l'accesso ai dati più in profondità nel grafico degli oggetti. In particolare i dati DPA che si appendono fuori legale all'interno del paese.

Il codice di cui sopra sta semplicemente mappando le informazioni del modello in un formato più semplice per ViewModel. La mia domanda è: consideri questa navigazione abbastanza profonda del buon esercizio del grafico o estrai il recupero degli oggetti più in basso nel grafico in repository?

risposta

14

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.

+0

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ò. –

+0

@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

+0

"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

3

Dipende dalla quantità di informazioni che si stanno utilizzando in qualsiasi momento.

Ad esempio, se si desidera ottenere il nome del paese per una persona (person.Pathway.Country.Name), qual è il punto di idratazione di tutti gli altri oggetti dal database?

Quando ho solo bisogno di una piccola parte dei dati tendo a tirare fuori solo ciò che userò. In altre parole, proietterò in un tipo anonimo (o in un tipo concreto appositamente realizzato se I deve avere uno).

Non è una buona idea estrarre un intero oggetto e tutto ciò che è relativo a quell'oggetto ogni volta che si desidera accedere ad alcune proprietà. Che cosa succede se lo fai una volta ogni postback o anche più volte? In questo modo potresti rendere la vita più facile a breve termine a costo di rendere la tua applicazione meno scalabile a lungo termine.

Come ho dichiarato all'inizio, tuttavia, non esiste una regola adatta a tutte le dimensioni, ma direi che è raro che sia necessario idratare così tante informazioni.

Problemi correlati