Was ist der beste Weg, um den Entity Framework-Datenbankkontext (Modell) mit ViewModel in MVVM WPF zu verbinden?

9

Wie in der obigen Frage: Wie kann das Entity Framework-Datenbankmodell (Kontext) am besten mit viewModel in MVVM (WPF) verbunden werden?

Ich lerne MVVM-Muster in WPF. Viele Beispiele zeigen, wie ein Modell in viewModel implementiert wird. Modelle in diesen Beispielen sind jedoch nur einfache Klassen. Ich möchte MVVM zusammen mit dem Entity-Framework-Modell verwenden (Basis-First-Ansatz). Was ist der beste Weg, um das Modell mit viewModel zu verbinden?

Danke für die Antworten.

//ctor of ViewModel 
public ViewModel()
{ 
db = new PackageShipmentDBEntities(); // Entity Framework generated class

ListaZBazy = new ObservableCollection<Pack>(db.Packs.Where(w => w.IsSent == false)); 
}

Dies ist mein üblicher Ctor von ViewModel. Ich glaube, es gibt einen besseren Weg. Ich habe über das Repository-Muster gelesen und bin mir nicht sicher, ob ich dies an WPF MVVM anpassen kann

hal9k2
quelle

Antworten:

4

Ich habe mir das ziemlich genau angesehen und keine "perfekte" Lösung gefunden. Das Repository-Muster funktioniert wunderbar für MVC-Anwendungen, bei denen der Kontext nur von kurzer Dauer ist, da er in einem kurzlebigen Controller vorhanden ist. Das Problem tritt jedoch auf, wenn Sie versuchen, dieselbe Struktur auf eine wpf-App anzuwenden, bei der die VM über einen längeren Zeitraum bestehen bleiben kann.

Ich habe diese Lösung in der Vergangenheit verwendet, die viel einfacher ist als viele der Repo-Muster, die ich gesehen habe und die versuchen, Dinge extrem zu abstrahieren, was zu nahezu unlesbaren Mengen an Code führt, die schwer zu debuggen sind. Hier sind die Schritte ...

  1. Erstellen Sie ein separates Projekt, damit EDMX als Datenzugriffsschicht fungiert
  2. Erstellen Sie unter demselben Projekt einen Ordner "Repositorys"
  3. Erstellen Sie eine Basisklasse "BaseRepository" als "Arbeitseinheit". IDisposableermöglicht es Ihnen, dies in a zu verwenden, using(){}und partialermöglicht es Ihnen, andere Repositorys zu implementieren

    public partial class MyEntityRepository : IDisposable
    {
        MyEntities context = new MyEntities();
    
        public void Dispose()
        {
            context.Dispose();
        }
    }
  4. Erstellen Sie eine weitere Datei mit dem Namen "MyOtherRepository". Erstellen Sie dieselbe Teilklasse, implementieren Sie jedoch Methoden basierend auf dem, was diese Datei enthalten soll

    public partial class MyEntityRepository
    {
        public void MyOtherMethodSave(EntityObject obj)
        {
            //work with context
            ...
    
            context.SaveChanges();
        }
    }

Jetzt können Sie dies in Ihrer VM tun ...

using(MyEntityRepository repo = new MyEntityRepository())
{
     repo.MyOtherMethodSave(objectToSave);
}

Dadurch werden alle Ihre Repositorys unter einer Klasse zusammengefasst, sodass Sie sich nicht mit einem separaten Kontext befassen müssen. Sie können verschiedene Repos besser verwalten, indem Sie die Methoden in verschiedene Dateien gruppieren, und so verhindern, dass Code dupliziert wird. Darüber hinaus sind Ihre Kontexte so kurzlebig wie ohne dieses Muster.

Der Nachteil ist, dass Sie bei größeren Systemen möglicherweise viele Methoden haben, die unter Ihrem Repo gebündelt werden. Eine Lösung in diesem Fall wäre, einige grundlegende allgemeine Befehle wie "Suchen" oder "Hinzufügen" zu implementieren und spezielle Befehle in ihrem jeweiligen Repository zu implementieren.

Schuh
quelle
2
Sie können den EF-eigenen Kontext von 'MyEntityRepository' ersetzen und erhalten das gleiche Ergebnis. Es sei denn, Sie möchten den EF-Kontext mit Ihrem eigenen "Repository" umschließen, wodurch die Duplizierung zunimmt.
Euphoric
@Euphoric Ja, Sie könnten, aber dann können Sie nicht garantieren, dass das Repository über den Kontext verwendet wird. Der springende Punkt ist, die Art und Weise, wie EF arbeitet, in einfache Geschäftsanforderungen zu abstrahieren
Schuh
4

Im Gegensatz zu Repositories, die ich nicht mag. Ich würde empfehlen, das von Ayende empfohlene Befehlsmuster zu verwenden .

Einfach gesagt, erstellen Sie für jede Operation eine separate ThisOperationCommandKlasse. Innerhalb dieser Klasse arbeiten Sie mit normalem EF-Kontext. Sie können sogar eine Basisklasse verwenden EFCommand, die einige Installationsarbeiten für Sie erledigt.

Auf der ViewModel-Seite erstellen Sie eine Instanz dieses Befehls, füllen ihn mit Parametern (Sie können sogar die gesamte ViewModel-Instanz übergeben, wenn Sie nichts gegen eine enge Kopplung zwischen dem Befehl und ViewModel haben) und übergeben ihn dann an eine ExecuteMethode, die gestartet wird Erhöhen Sie den Befehl, führen Sie ihn aus, reißen Sie ihn ab und geben Sie dann alles zurück, was der Befehl erhalten hat. Sie können auch mehrere Werte zurückgeben lassen, wenn Sie es nach der Ausführung von der Instanz des Befehls erhalten.

Der Vorteil ist, dass Sie nicht die gesamte Datenzugriffsschicht als Reposotory duplizieren müssen und Befehle wiederverwenden und verfassen können, solange Sie eine einfache Infrastruktur erstellen, um dies zu unterstützen. Zum Beispiel Befehle von anderen Befehlen ausführen.

Euphorisch
quelle
0

Für einfache Szenarien habe ich Folgendes verwendet:

public class ViewModel : IDisposable {

    private EntitiesContext _context = new EntitiesContext();

    private SomeEntity _model;
    public SomeEntity Model {
       get { return _model; }
    }

    public View(int id) {
        _model = _context.SomeEntity.Find(id);
    }

    private ICommand _saveCommand = new RelayCommand(() => _context.SaveChanges());
    public ICommand SaveCommand {
        get { return _saveCommand; }
    }        

    public void Dispose() {
         _context.Dispose();
    }

}
Mike
quelle
1
Das Problem dabei ist, dass Ihr Kontext jetzt möglicherweise "langlebig" ist.
Schuh
1
Sie sollten die Instanz des Kontexts nicht innerhalb der Klasse erstellen, sondern stattdessen in den Konstruktor einfügen.
Oscar Mederos