Laden...

Wie halte ich mein ViewModel aktuell nach einem Datenbank-Update?

Erstellt von JimStark vor 3 Jahren Letzter Beitrag vor 3 Jahren 780 Views
Hinweis von MrSparkle vor 3 Jahren

Abgeteilt von Wie kann man unter WPF ein neues Fenster MVVM-konform öffnen?

JimStark Themenstarter:in
309 Beiträge seit 2020
vor 3 Jahren

Hey noch eine weiterführende Frage:

Ich arbeite in meiner Datenbank mit "Order"-Objekten, diese mappe ich mir in "OrderViewModels" für WPF,...

Speichere ich z.B. ein Objekt ab, lese ich danach wieder die Datenbank aus.


            // "Order"-Objekte aus der Datenbank
            var orders = await _SqlRepo.GetOrders();
            // Liste mit ViewModels (werden in Window abgerufen)
            _Orders.Clear();
            
            foreach(var order in orders)
            {
                var vm = new OrderViewModel(order);

                _Orders.Add(vm);
            }

Durch das Clearen gehen ja jedesmal die Referenzen verloren, wenn z.B. ein Fenster mit Details das jeweilige OrderViewModel noch verwendet. Das funktioniert zwar, ich kann Änderungen dann aber nur noch an einer Stelle tracken.

Gibt es ein fertiges Pattern mit dem ich erst die bestehenden ersetze (z.B. anhand OrderID identifiziere), dann nicht mehr vorhandene (gelöschte) entferne und neu hinzugefügte, neu erstelle?
Das kann man natürlich alles von Hand machen, ich schätze das Problem ist aber sicher schon öfter vorgekommen, ich weiß nur nicht nach was ich suchen soll.

W
955 Beiträge seit 2010
vor 3 Jahren

... dann lerne doch LINQ. Damit isr dein gezeigter Code ein Zweizeiler. Und für das Anfügen und Entfernen gibt es Except, Union und Where.

5.658 Beiträge seit 2006
vor 3 Jahren

@witte: Das würde aber nichts an dem Problem ändern.

@JimStark: Kannst du bitte zukünftig [Hinweis] Wie poste ich richtig? beachten, besonders Punkt 1.2: Nur ein Thema pro Thread? Wir müssen jedesmal deine Beiträge verschieben...

Zu deinem Problem: Wenn der Benutzer das ViewModel geändert hat, und die Änderungen in die Datenbank geschrieben wurden, dann ist doch das ViewModel auf dem aktuellen Stand. Wozu sollte man dann alles noch einmal neu laden?

Das wäre nur notwendig, wenn die Daten außerhalb der Anwendung geändert wurden. Und dann darfst du die ViewModels eben nicht ersetzen, sondern mußt die vorhandenen anpassen.

Weeks of programming can save you hours of planning

2.079 Beiträge seit 2012
vor 3 Jahren

Ich hab mir dafür mal eine generische Liste geschrieben, die neben INotifyCollectionChanged auch passende Methoden bietet, die vorhandene Objekte ersetzen kann.
Intern war es im Wesentlichen ein Dictionary mit der ID als Key und der ViewModel als Value.
Die ViewModels mussten dann natürlich Funktionalität zum Aktualisieren der Daten (Ein Interface mit einer UpdateData(TModel)) haben und die Liste hat dann aus den übergebenen Models die IDs gesucht und entsprechend aktualisiert, erzeugt oder entfernt.

Ein Pattern in dem Sinne gibt es nicht (ode ist mir nicht bekannt), da das Problem viel zu spezifisch ist oder sein kann.

NuGet Packages im Code auslesen
lock Alternative für async/await

Beim CleanCode zählen nicht die Regeln, sondern dass wir uns mit diesen Regeln befassen, selbst wenn wir sie nicht befolgen - hoffentlich nach reiflichen Überlegungen.

JimStark Themenstarter:in
309 Beiträge seit 2020
vor 3 Jahren

Hi,

danke für eure Tipps,

habe es mir jetzt doch nochmal etwas umgeschrieben, das funktioniert soweit jetzt. Falls jemand es brauchen sollte:


            // Modelle von Datenbank beziehen:
            var orders = _SqlRepo.GetOrders();
            orders.Wait();


            // Modelle die in ViewModel Liste bereits referenziert sind:
            var ordersToReplace = _Orders.Where(
                c => 
                orders.Result.FirstOrDefault(old => old.OrderID == c.OrderID) != null)
                .ToList();
            
            
            // vorhandene ViewModels ersetzen:
            ordersToReplace.Select(
                c => 
                c = new OrderViewModel(
                    orders.Result.Where(c => c.OrderID == c.OrderID).First()
                    )
                );

            // ViewModels, für die es kein Modell gibt ==> löschen
            var ordersToDelete = _Orders.Where(
                vm => 
                orders.Result.FirstOrDefault(model => model.OrderID == vm.OrderID) == null)
                .ToList();

            foreach(var orderToDelte in ordersToDelete)
                _Orders.Remove(orderToDelte);


            // Models, für die es kein ViewModel gibt ==> hinzufügen:
            var ordersToAdd = orders.Result.Where(
                c => _Orders.FirstOrDefault(vm => vm.OrderID == c.OrderID) == null)
                .ToList();

            // ViewModel für Modell erstellen & hinzufügen:
            foreach (var order in ordersToAdd)
                _Orders.Add(new OrderViewModel(order));

D
261 Beiträge seit 2015
vor 3 Jahren

Ersatz du hier mit:

// vorhandene ViewModels ersetzen:
ordersToReplace.Select(
    c =>
    c = new OrderViewModel(
        orders.Result.Where(c => c.OrderID == c.OrderID).First()
        )
    );

... nicht genauso das komplette Objekt (inkl. Referenz) wie mit dem Code in deinem initialen Post?

JimStark Themenstarter:in
309 Beiträge seit 2020
vor 3 Jahren

Ich glaube ich habe mein Problem nicht deutlich genug erläutert.

Als Beispiel habe ich ein Objekt der ViewModel-Liste gebunden, und zeig in einer TextBox ein Feld davon. Wenn ich zwischenzeitlich die Objekte neu lade und danach die TextBox änder, konnte ich in der Liste die Änderung nicht mehr nachverfolgen, da ja die Referenz verloren ging (durch Clear).
Mit dem Code geht es jetzt. Also die "Referenz" ist scheinbar die selbe, sie wurde nur ersetzt.

5.658 Beiträge seit 2006
vor 3 Jahren

Der Code, den dannoe gepostet hat, ersetzt genau gar nichts 😃
Es werden neue OrderViewModels erzeugt, und dann verworfen, da mit dem Ergebnis nichts gemacht wird. Da die Enumeration selbst gar nicht durchlaufen wird, z.B. mit ToList(), werden noch nicht einmal die OrderViewModels erzeugt.

Entweder ist der Code aus dem Zusammenhang gerissen, oder du hast nicht richtig getestet. Am besten schreibt man sich für so etwas Unit Tests, dann kannst du sicher sein, daß der Code macht, was er soll. Siehe dazu: [Artikel] Unit-Tests: Einführung in das Unit-Testing mit VisualStudio

Aber was du zu der TextBox schreibst, klingt eher nach einem Problem mit dem UI-Design.

Weeks of programming can save you hours of planning

JimStark Themenstarter:in
309 Beiträge seit 2020
vor 3 Jahren

Du hast recht, das ist mir gar nicht aufgefallen. Ich habe jetzt eine Update Methode dafür geschrieben. Damit geht es jetzt. Danke!