2010-10-13 5 views
11

Wir haben eine ASP.NET MVC-Site, die Entity Framework-Abstraktionen mit Repository und UnitOfWork-Mustern verwendet. Ich frage mich, wie andere die Navigation komplexer Objektgraphen mit diesen Mustern implementiert haben. Lassen Sie mich ein Beispiel von einem unserer Controller geben:Muster zum Abrufen komplexer Objektdiagramme mit Repository Pattern mit 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 
    }; 

Es ist eine Registrierung und so ziemlich alles hängt die POCO-Klasse Person ab. In diesem Fall cachen wir die Person durch den Registrierungsprozess. Ich habe jetzt damit begonnen, den letzten Teil des Registrierungsprozesses zu implementieren, der Zugriff auf Daten benötigt, die tiefer im Objektdiagramm liegen. Speziell DPA-Daten, die von Legal Inside Country abhängen.

Der obige Code dient nur dazu, die Modellinformationen in ein einfacheres Format für das ViewModel zu übertragen. Meine Frage ist, ob Sie diese ziemlich genaue Navigation des Diagramms als gute Praxis betrachten oder ob Sie das Abrufen der Objekte weiter unten im Diagramm in Repositories abstrahieren würden.

Antwort

14

Meiner Meinung nach ist die wichtige Frage hier - haben Sie LazyLoading deaktiviert?

Wenn Sie nichts getan haben, ist es standardmäßig aktiviert.

Also, wenn Sie Person.Pathway.Country tun, werden Sie einen anderen Aufruf an den Datenbankserver aufrufen (es sei denn, Sie tun eifrig laden, worüber ich in einem Moment sprechen werde). Wenn Sie das Repository-Muster verwenden, ist das ein großes Nein. Controller sollten keine direkten Aufrufe an den Datenbankserver verursachen.

Sobald ein C ontroller die Informationen aus dem M odel erhalten hat, sollte es fertig sein Vorsprung zu tun (falls erforderlich), und übergeben Sie auf die V iew, gehen nicht zurück zum M.

Aus diesem Grunde in unserer Implementierung (wir auch Repository verwenden, EF4 und Arbeitseinheit), wir Lazy Loading- und erlauben den Durchgang durch die Navigationseigenschaften über unsere Service-Schicht (eine Reihe von „deaktivieren Fügen "Aussagen, die durch Aufzählungen und Erweiterungsmethoden verfeinert werden."

Wir dann eifrig-laden diese Eigenschaften wie die Controller erfordern sie. Aber das Wichtigste ist, der Controller muss sie explizit anfordern.

Was im Grunde erzählt die Benutzeroberfläche - "Hey, Sie erhalten nur die Kerninformationen über diese Entität. Wenn Sie etwas anderes wollen, fragen Sie danach".

Wir haben auch einen Service Layer Vermittlung zwischen den Controllern und dem Repository (unsere Repositories geben IQueryable<T> zurück). Dies ermöglicht dem Repository, sich aus dem Geschäft mit komplexen Assoziationen zu befreien. Das eifrige Laden wird auf der Service-Ebene durchgeführt (sowie Dinge wie Paging).

Der Vorteil der Serviceschicht ist einfach - mehr lose Kopplung. Das Repository behandelt nur Add, Remove, Find (was IQueryable zurückgibt), Unit of Work behandelt das "Newing" von DCs und Commit von Änderungen. Die Service-Schicht übernimmt die Materialisierung von Entitäten in konkrete Collections.

Es ist ein schöner, 1-1 stapelartigen Ansatz:

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) 

Wir haben noch nicht auf die MVC-Schicht nach oben (wir TDD tun), sondern eine Dienstschicht ein weiterer Ort sein könnte, Sie könnten die Kernelemente in ViewModels hydratisieren. Und wieder - es wäre die Entscheidung des Controllers, wie viele Informationen er wünscht.

Auch hier geht es um eine lose Kopplung. Ihre Controller sollten so einfach wie möglich sein und sich nicht um komplexe Zusammenhänge kümmern.

In Bezug auf wie viele Repositories, ist dies ein hoch diskutiertes Thema. Einige mögen eine pro Entity haben (Overkill, wenn du mich fragst), einige gruppieren basierend auf Funktionalität (macht Sinn in Bezug auf Funktionalität, einfacher zu arbeiten), aber wir haben eine pro Aggregat-Wurzel.

Ich kann nur auf dem Modell vermuten, dass „Person“ sollte die einzige Aggregat root ich sehen kann.

Daher macht es nicht viel Sinn, ein anderes Repository mit „Pathways“ zu handhaben, wenn ein Weg immer mit einem bestimmten „Person“ zugeordnet ist. Das Personen-Repository sollte dies handhaben.

wieder - vielleicht, wenn Sie Ihre EDMX screencapped, könnten wir Ihnen weitere Tipps geben.

Diese Antwort könnte auf Grund des Umfangs der Frage etwas zu weit ausgedehnt sein, aber ich dachte, ich würde eine gründliche Antwort geben, da wir gerade mit genau diesem Szenario zu tun haben.

HTH.

+0

Danke, hat Ihre Antwort sicherlich mein Denken zu klären. Die Antworten haben mir geholfen, zu erkennen, wenn ich meinen Code betrachte, bin ich besorgt darüber, was EF hinter den Kulissen tut, um diese Objektgraphen zu realisieren. Ich weiß, dass ich SQL Profiler hochfahren kann, um zu sehen, was vor sich geht, aber mein erster Gedanke ist, dass eine bessere Kontrolle in der Zukunft eine bessere Kontrolle in der Zukunft bedeutet, sollte die Leistung oder die Anforderung, diese Daten an entfernte Quellen zu liefern, eine Anforderung werden. Ihr Vorschlag einer Service-Schicht zwischen den Controllern und den Repositories ist etwas, das ich untersuchen werde. –

+0

@Daz Lewis - definitiv. Wir haben eine API für unsere Website. Aus diesem Grund haben wir die Service-Schicht. Sowohl unsere Website als auch API sind "Kunden". Dies ermöglicht ein schönes, fließendes (und dennoch dichtes) Programmiermodell.BTW - Sie müssen nicht SQL Profiler verwenden. Es gibt eine Methode für ObjectQuery namens .ToTraceString. Wir verwenden dies mit Protokollierung, alle unsere Repository-Methoden debuggen diese Zeile (Info-Ebene), so dass wir sehen können, was ausgeführt wird. Wie auch immer, schauen Sie sich definitiv die Service-Schicht an. Unsere Repositories sind sehr einfach - werfen Sie einen Blick auf einige meiner Fragen, um zu sehen, wie ich es gemacht habe. – RPM1984

+0

"Controller sollten keine direkten Aufrufe an den Datenbankserver verursachen". Danach sollte Ihr Controller kein Repository aufrufen, um direkte Aufrufe an den Datenbankserver zu verursachen. Beim Zugriff auf eine Eigenschaft, die Lazy-geladen werden soll, wird kein direkter Aufruf an den Datenbankserver auf die gleiche Weise ausgelöst, wie in Ihrem Repository ein direkter Aufruf an den Datenbankserver erfolgt. Ja, es führt zwar zum Aufruf des Datenbankservers, aber indirekt über Ihre Infrastruktur mit einem ORM-Tool. – adriaanp

3

Es hängt davon ab, wie viele der Informationen Sie gleichzeitig verwenden.

Zum Beispiel, wenn Sie nur den Namen des Landes für eine Person (person.Pathway.Country.Name) erhalten möchten, was ist der Punkt in der Befeuchtung aller anderen Objekte aus der Datenbank?

Wenn ich nur einen kleinen Teil der Daten brauche, ziehe ich einfach heraus, was ich verwenden werde. Mit anderen Worten, ich projiziere in einen anonymen Typ (oder einen speziell angefertigten Betontyp, wenn ich muss einen haben).

Es ist keine gute Idee, jedes Mal, wenn Sie auf einige Eigenschaften zugreifen wollen, ein ganzes Objekt und alles, was zu diesem Objekt gehört, herauszuziehen. Was ist, wenn Sie dies einmal jeden Postback oder sogar mehrmals machen? Auf diese Weise können Sie das Leben auf kurze Sicht erleichtern, indem Sie Ihre Anwendung langfristig weniger skalierbar machen.

Wie ich schon am Anfang sagte, gibt es dafür keine einheitliche Regel, aber ich würde sagen, dass es selten ist, dass Sie so viele Informationen hydratisieren müssen.

Verwandte Themen