Verwalten von DbContext in WPF MVVM-Anwendung

8

Damit habe ich tagelang den Kopf getroffen und kann mich immer noch nicht entscheiden, welcher der richtige Ansatz ist Diese Frage zielt speziell auf WPF ab, da im Gegensatz zu einer Web-Anwendung viele Online-Beiträge und Artikel eine context pro view-model -Ansicht und keine context pro request empfehlen.
Ich habe eine WPF MVVM -Anwendung, die ein Entity-Framework DB first -Modell verwendet.
Hier ist ein Beispiel für zwei Modelle, die in meiner App verwendet werden (erstellt von EF Designer):

%Vor%

Ich habe meine Möglichkeiten eingeschränkt, wie dies mit folgendem zu tun ist:

1) Erstellen einer DataAccess -Klasse, die den DbContext bei jedem Methodenaufruf erstellt und entledigt:

%Vor%

was ich in meinem ViewModel wie folgt verwenden kann:

%Vor%

2) Ähnlich wie Ansatz 1, aber ohne die Using -Anweisungen:

%Vor%

Die Verwendung ist innerhalb von ViewModel

identisch

3) Erstellen Sie ein repository für jedes entity . Sieht genauso aus wie die obigen Optionen (hat auch das mit oder ohne using dilemma), aber jedes Repository enthält nur Methoden, die sich auf seine entity beziehen.
Afaik die Verwendung ist die gleiche wie oben in meinem ViewModel .

4) Erstellen Sie eine Klasse Unit-Of-Work , die bei Bedarf die entsprechende Repository übergibt:

%Vor%

und benutze es in meinem ViewModel wie folgt:

%Vor%

Welcher der obigen Ansätze (falls vorhanden) wird in Bezug auf Daten-Parallelität, bessere Abstraktion und Layering und Gesamtperformance bevorzugt?
BEARBEITEN Fand den folgenden Absatz in Dieser Artikel. :

  

Verwenden Sie bei der Arbeit mit Windows Presentation Foundation (WPF) oder Windows Forms eine Kontextinstanz pro Formular. Auf diese Weise können Sie die Änderungsnachverfolgungsfunktion verwenden, die der Kontext bereitstellt.

Es stellt sich jedoch die Frage, ob ich ein DbContext -Objekt in meinem view-model erstellen soll oder ob es besser ist, eine Utility-Klasse wie meine DAL -Klasse zu haben und darauf zu verweisen.

    
Yoav 26.10.2014, 08:44
quelle

1 Antwort

1

Dies ist, was Dependency-Injection-Frameworks lösen sollen. Ja, es ist eine weitere Technologie, die Sie Ihrem Projekt hinzufügen können, aber wenn Sie anfangen, DI zu verwenden, schauen Sie nie mehr zurück.

Das eigentliche Problem hier ist, dass Sie versuchen, diese Entscheidung in Ihren Betrachtungsmodellen zu treffen, wenn Sie wirklich eine Inversion der Kontrolle einsetzen und die Entscheidung höher machen sollten. Eine WPF / MVVM-Anwendung benötigt ein Kontext-Formular, so dass Änderungen erst nach Abschluss der Bearbeitung eines Benutzers übermittelt werden und dem Benutzer die Möglichkeit gegeben wird, die Änderungen abzubrechen. Ich weiß, dass Sie dies nicht in einer Webanwendung verwenden, aber eine gut durchdachte Architektur bedeutet, dass Sie in der Lage sein sollten, in welchem ​​Fall Sie einen Kontext pro Anfrage wünschen. Möglicherweise möchten Sie ein Konsolen-App-Dienstprogramm schreiben, das die Datenbank mit statischen Daten füllt. In diesem Fall möchten Sie möglicherweise einen globalen / Singleton-Kontext für Leistung und Benutzerfreundlichkeit. Schließlich müssen Ihre Komponententests auch den Kontext überspielen, wahrscheinlich auf einer Testbasis. Alle vier dieser Fälle sollten in Ihrem Injektionsrahmen eingerichtet werden, und Ihre Sichtmodelle sollten sich über keine von ihnen bewusst sein.

Hier ist ein Beispiel. Ich benutze Ninject, das speziell für .NET entwickelt wurde. Ich bevorzuge auch NHibernate, obwohl die Wahl von ORM hier irrelevant ist. Ich habe Session-Objekte, die unterschiedliche Scoping-Anforderungen haben, und dies wird in einem Ninject-Modul eingerichtet, das meine ORM-Klassen initialisiert:

%Vor%

Dies legt das Scoping für eine ISession fest, die dem NHibernate-Äquivalent Ihrer Kontextklasse entspricht. Meine Repository-Klassen, die die Datenbankobjekte im Arbeitsspeicher verwalten, enthalten einen Verweis auf die Sitzung, der sie zugeordnet sind:

%Vor%

Das [Inject] -Attribut weist Ninject an, dieses Feld automatisch mit den von mir eingerichteten Scoping-Regeln zu füllen. Bisher passiert das alles in meinen Domain-Klassen, aber es erstreckt sich auch auf meine View-Model-Ebene. In meinen Scoping-Regeln gebe ich ein Objekt namens "ScreenScope" ein, und obwohl ich hier nicht darauf eingehen werde, bedeutet das grundsätzlich, dass ich jedes Mal ein Session-Objekt in meinem ScreenViewModel oder beliebige View-Models als Mitglieder anfordere ( einschließlich ihrer eigenen Kinder) wird das gleiche ISession-Objekt automatisch erstellt und an alle übergeben. Durch die Verwendung von DI-Scoping muss ich nicht einmal darüber nachdenken, ich erkläre einfach die Mitglieder mit dem [Inject] -Attribut und es passiert:

%Vor%

Diese Serviceklassen enthalten alle einen RepositoryManager, der injiziert wurde, und da sie alle in ScreenViewModel enthalten sind, ist das ISession-Objekt identisch, zumindest in meinem WPF-Build. Wenn ich zu meinem MVC-Build wechsle, sind sie für alle View-Modelle, die für eine bestimmte Anfrage erstellt wurden, gleich, und wenn ich zu einem Console-Build wechsle, verwendet es dieselbe ISession für alles im gesamten Programm.

TL; DR: Verwenden Sie die Abhängigkeitsinjektion und einen Bereich, in dem Ihre Kontexte zu einem pro Formular gehören.

    
Mark Feldman 29.07.2015 00:49
quelle