Entity Framework + WPF -> Objekt speichern aus ObservableCollection wie?

  • C#

Es gibt 5 Antworten in diesem Thema. Der letzte Beitrag () ist von xChRoNiKx.

    Entity Framework + WPF -> Objekt speichern aus ObservableCollection wie?

    Hallöchen,

    erstes Projekt komplett mit dem EntityFramework... Ich verstehe das Prinzip und komme soweit auch klar.

    Nun habe ich die Situation:

    Ich lese alle Customer aus in eine ObservableCollection<Customer> aus der DB:

    C#-Quellcode

    1. public void ReloadCustomer()
    2. {
    3. using (ShipperContext db = new ShipperContext())
    4. {
    5. CustomerList.Clear();
    6. foreach (Customer cust in db.Customers)
    7. {
    8. CustomerList.Add(cust);
    9. }
    10. }
    11. }


    Bisher kein Problem...

    In meiner View habe ich jetzt eine Listbox und rechts daneben ein UCL das an das jeweilige SelectedCustomer Object gebunden ist.
    Ich kann also in den Textboxen die Propertys des Customer Objects bearbeiten... Doch wie Speicher ich das?

    Muss ich einen GLOBALEN DbContext nutzen? Kann ich irgendwie nur sagen SaveChanges(object)? was ist da best practice?
    Bisher hab ich nur gesehen das die Leute einen globalen DbContext haben aber das scheint mir eher kontraproduktiv? was ist wenn die DB einen Verbindungsabruch hat?
    Oder verbindet sich der Context nur dann zu DB beim lesen / schreiben?

    hoffe jemand kann da etwas Licht ins dunkle bringen.
    Grüße , xChRoNiKx

    Nützliche Links:
    Visual Studio Empfohlene Einstellungen | Try-Catch heißes Eisen
    Hallo

    Das kommt darauf an.

    Du kannst dir eine lokale Variable machen welche den Kontext hält um Änderungen (!!) speichern zu können.
    Solange der ChangeTracker von EF "dabei" ist bekommt er mit was geändert wurde und speichert die Änderungen mittels SaveChanges() zurück.

    Generell gilt aber dennoch (um unangnehme Nebeneffekte zu vermeiden) das man den Kontext immer nur so lange verwendet wie dieser benötigt wird und dann Disposed.

    Du kannst natürlich auch jederzteit eine Entität oder auch nur Teile (also einzelne Properties) als "geändert" markieren und dem ChangeTracker sagen "Pass auf, dieses und jenes hat den Status "Changed" oder "New" oder "Deleted"".

    Generell nicht der ChangeTracker allerdings Performance weg und sollte immer nur aktiv sein wenn an einer Entität wirklich etwas geändert wird/werden kann. Anstonsten sollte mit .AsNoTracking() abgerufen werden da dies gerade bei größeren Selects viel Performanter ist. Zudem versuche ich sogar immer mit Projektion zu arbeiten. Also das Select nur auf die Spalten zu beschrenken die ich wirklich benötige, alles unnötige muss ich ja nicht unbedingt übertragen und/oder im RAM halten.

    Bei deinem Code von oben würde ich dir noch dazu raten in einer ForEach UNBEDINGT mit .ToList() vorher explizit den Roundtrip zur Datenbank zu machen. So gabs in der vergangenheit hier und da Probleme. Und es ist besser man gewöhnt sich das einfach an.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Hallo,

    erstmal danke euch beiden.

    @Nofear23m bisher nutze ich using mit dem Context lade ja alle daten und dann fertig.
    Wie kann ich bei der Methode denn dem ChangeTracker bescheid geben?

    Kann ich beim Speichern einen neuen Context nutzen und ihm irgendwie das geänderte object geben?
    Weil ich weiß ja welches Object geändert wurde (SelectedItem).
    Grüße , xChRoNiKx

    Nützliche Links:
    Visual Studio Empfohlene Einstellungen | Try-Catch heißes Eisen

    xChRoNiKx schrieb:

    Kann ich beim Speichern einen neuen Context nutzen und ihm irgendwie das geänderte object geben?
    Weil ich weiß ja welches Object geändert wurde (SelectedItem).


    Ja, sicher geht das. Bei größeren Daten wie z.b. in einem DataGrid empfielt sich das sogar weil du dann den Abruf mit AsNoTracking() machen kannst und somit der Abruf super Performant ist.

    Du hast nun mehrere Möglichkeiten:

    context.Update(entity) updated eine Entität wenn ein Auto-Generierter Key vorhanden ist (ID Spalte). Ist die ID (die musst du unbedingt mit abrufen) großer 0 (gesetzt dem Fall das die ID von Typ int ist und nicht GUID) wird die Entität automatisch als "CHANGED" von EF gekennzeichnet, ansonsten automatisch als "NEW".

    Oder du markierst die Entität als Modified. Das klappt dann auch wenn Changetracking abgeschaltet ist.
    _ctx.Entry(entität).State = EntityState.Modified; oder sogar nur eine gewisse Eigenschaft (dann ist das Update-Statement auch schlanker da nicht alle Spalten upgedatet werden was Konflikte vermindert) mit _ctx.Entry(entität).Property(x => x.die Eigenschaft).IsModified = true;

    Rufst du aber nicht Hunderte oder tausende Datensätze ab würde ich persönlich den Changetracker mitschaun lassen. Spricht ich lass den Context offen und Dispose ihn beim schliessen des Views.
    So weis dieser immer ob was geändert wurde. und du kannst dies auch immer abrufen mit _ctx.ChangeTracker.HasChanges(). Dieses gibt dir ein bool zurück und bei _ctx.SaveChanges() bekommst du ja dann eh ein int zurück welches dir anzeigt wieviele Datensätze gespeichert wurden.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##