Laden...

Asp.Net MVC Model zwischen Actions übergeben

Erstellt von itstata vor 13 Jahren Letzter Beitrag vor 12 Jahren 3.848 Views
I
itstata Themenstarter:in
302 Beiträge seit 2008
vor 13 Jahren
Asp.Net MVC Model zwischen Actions übergeben

Hallo Leute,

ich hab ein Objekt Zeiterfassung welches in der Businesslogik eine Funktion CreateZeiterfassung() hat. Dort wird einfach ein neues Objekt mit einigen Standardwerten (wie z.B. Datum = Datetime.Now etc.) angelegt. Da ich diese Logik auch in einer Wpf-Anwendun nutze möchte ich diese Funktion auch im Web-Frontend nutzen.
Hier einmal der Code, wie ich es derzeit realisiert habe:


public ActionResult Edit(int id)
        {
            var zeiterfassung = Zeiterfassungen.SingleOrDefault(a => a.ZeiterfassungId == id);
            if (zeiterfassung == null)
            {
                zeiterfassung = EntityService.ZeiterfassungenService.CreateZeiterfassung();
            }

            var auftraege = EntityService.Auftraege.ToList();
            FillDropDownLists(zeiterfassung.ZeiterfassungId, zeiterfassung.AuftragId);
            return View("Edit", zeiterfassung);
        }

In der Edit-Action wird also einfach ein neues Objekt angelegt. Ist das Objekt bereits vorhanden wird das vorhandene Objekt angezeigt. Soweit alles klar.


        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Save(Zeiterfassung zeiterfassung)
        {
            try
            {
                var zeiterfassungFromDb = EntityService.ZeiterfassungenService.Zeiterfassungen.SingleOrDefault(a => a.ZeiterfassungId == zeiterfassung.ZeiterfassungId);
                
                if (zeiterfassungFromDb == null)
                {
                    zeiterfassungFromDb = EntityService.ZeiterfassungenService.CreateZeiterfassung();
                }

                zeiterfassung.Auftrag = EntityService.Auftraege.SingleOrDefault(a => a.AuftragId == zeiterfassung.AuftragId);
                zeiterfassung.Taetigkeitart = EntityService.ZeiterfassungenService.Taetigkeitarten.SingleOrDefault(t => t.TaetigkeitartId == zeiterfassung.TaetigkeitartId);
                zeiterfassung.Person = GetMitarbeiter();
                TryUpdateModel(zeiterfassungFromDb);
                
                string validationList = zeiterfassung.ValidationList();

                if (string.IsNullOrEmpty(validationList))
                {
                    EntityService.SaveChanges();
                }
                else
                {
                    ViewData["ValidationErrors"] = validationList;
                    FillDropDownLists(zeiterfassung.ZeiterfassungId, zeiterfassung.AuftragId);
                    return View("Edit", zeiterfassung);
                }

                return null;
            }
            catch
            {
                FillDropDownLists(zeiterfassung.ZeiterfassungId, zeiterfassung.AuftragId);
                return View("Edit");
            }
        }

Die Save-Action liest alle geänderten Werte ein und macht ein Update oder erstellt einen neuen Eintrag. Und jetzt kommt mein Problem: Mit diesem Code werden zwei Datensätze in der Datenbank angelegt (Variablen: 'zeiterfassung' und 'zeiterfassungFromDb'). Sieht jemand meinen Fehler?

16.842 Beiträge seit 2008
vor 13 Jahren

Prinzipiell gehört Dein UpdateModel ebenfalls ins if - macht ja kein Sinn ein Model zu aktualisieren, wenns Fehler enthält.

Das Verhalten, dass zwei Entities erstellt werden, ist mir auch schon öfter aufgefallen - aber eine wirklich stabile Lösung habe ich auch nicht gefunden.
Man liest auch immer wieder in den MSDN Foren, dass andere User ein ähnliches Problem haben; das ist also noch eine kleine Baustelle im Entity würde ich behaupten.
Bei mir lief's ne Zeit lang, bis ich meine Entity-Klasse um ein paar Properties erweitert habe - seit dem nicht mehr.

Meine Lösung ist jetzt, dass ich die Entity lösche und neu anlege.
Die Relationen werden bei mir sowieso sauber geknüpft und da ich mit GUIDs arbeite spielt das für mich und die Anwendung keine Rolle, wie die GUID aussieht.

Damit will ich Dich nicht entmutigen - ich fänds super, wennst eine stabile Lösung für das Problem finden würdest und bin selbst auch sehr daran interessiert.

I
itstata Themenstarter:in
302 Beiträge seit 2008
vor 13 Jahren

Oh je...da ahne ich ja nichts Gutes. Ich werd am Wochenende mal noch mal nach diesem Problem gucken. Vielleicht hab ich ja Glück. Meistens denkt man ja, dass das Problem vor dem Rechner sitzt.

T
307 Beiträge seit 2008
vor 13 Jahren

Ja also ich seh schon einen Fehler, und zwar folgender das die Oberfläche nicht richtig von der "Storage-Struktur" getrennt ist, sondern abhängig davon ist.
Das Entitiy-Zeugs hat im Controller gar nix zu suchen, da fehlt eindeutig noch eine Zwischenschicht und D wirst sehen die Probleme sind weg....

16.842 Beiträge seit 2008
vor 13 Jahren

Das Entitiy-Zeugs hat im Controller gar nix zu suchen

Kannst Du das begründen?
Bei POCO Entites ist es eine Voraussetzung, dass die Entity direkt im Controller vergeben wird, um Updatemodel direkt nutzen zu können. Das ist der Sinn des Models am Controller ⚠
Die Proxy-Schicht der POCOs ermöglicht dies ja gerade.

Gruß ABt

16.842 Beiträge seit 2008
vor 13 Jahren

Ich hab die Lösung für mein Problem gefunden; da mich die Behauptung von Taucher nun doch beschäftigt hat und ich die Lösung finden wollte.
Die Lösung ist viel simpler als gedacht und ich hatte bezüglich meiner Proxies recht:

MVC ermöglicht mit POCO Entities das direkte Modelbinding, was mit dem DefaultBinder auch wunderbar nachzuvollziehen ist.
Alle Änderungen, die anschließend mit einem db.SaveChanges() mitgeteilgt werden klappen einwandfrei.

Es ist also nichts anderes nötig als ein:

public ActionResult CommitEdit(MyEntity model)
{
   db.SaveChanges( );
   return View( );
}

UpdateModel bringt den Binder durcheinander, wodurch man einmal die aktualisierte, und einmal eine neue Entity in der Datenbank hat. Der Proxy wird hier neugesetzt und daher der doppelte Eintrag.

SaveChanges wirft eine Exception, wenn die Validierungen fehlschlagen - wie gewollt.

Hoffe geholfen zu haben.

Grüße

I
itstata Themenstarter:in
302 Beiträge seit 2008
vor 13 Jahren

Hallo,

gleiches Verhalten kann ich bei mir beobachten, aber ist das nicht ein Bug?

Ich meine, es gibt ja nur zwei Lösungen:

  1. Kein UpdateModel verwenden (manuelles Zuweisen der Änderungen)
  2. Context vorher von der zu aktualisierenten Entität befreien (also unsauber einfach löschen)
16.842 Beiträge seit 2008
vor 13 Jahren

Ich denke nicht, dass es ein Bug ist, da die POCO Entity ja automatisch gebunden ist.
Das "Problem" ist, dass die meisten MVC Beispiele mit LinqToEntity und einer lokalen mdf arbeiten, statt mit POCO Entities.
Jedenfalls konnte ich kein aktuelles Beispiel mit POCO Entites finden, die direkt ein Model binden, statt eine FormCollection.

Bei der FormCollection braucht man dieses Updatemodel. Das konnte ich so auch nachollziehen.

Gruß

I
itstata Themenstarter:in
302 Beiträge seit 2008
vor 13 Jahren

Noch eine kurze Nachfrage:

Bedeutet das, dass durch die Nutzung des Modelbindings gar kein UpdateModel mehr brauche? Ich hoffe ich hab dich da nicht falsch verstanden.

16.842 Beiträge seit 2008
vor 13 Jahren

Richtig.
Durch das Bindung über den Proxy der POCOs wird das Model bereits aktualisiert.

Um die Aktualisierungen nun auch noch zu übernehmen, muss SaveChanges des DataContext ausgeführt werden.
Sollte der Controller ohne SaveChanges verlassen werden, werden die Aktualisierungen verworfen.

I
itstata Themenstarter:in
302 Beiträge seit 2008
vor 13 Jahren

Na dann...Bestens. Danke für die Auflösung. Das ist aber auch scheiße Dokumentiert.

16.842 Beiträge seit 2008
vor 13 Jahren

Übrigens, was ich gerade lese...

Wieso denn

  1. Kein UpdateModel verwenden (manuelles Zuweisen der Änderungen)

?

Die Änderungen der Edit-Form werden automatisch im gebundenen Model vorgenommen.
Du brauchst hier absolut nichts manuell machen, nicht mal UpdateModel( ) musst Du ausführen - eben nur SaveChanges( ) (wenn die Validierung erfolgreich war)

16.842 Beiträge seit 2008
vor 13 Jahren

Da hat sich jemand ziemlich Mühe gemacht und das Problem lokalisiert
ASP MVC Binding Graph

I
itstata Themenstarter:in
302 Beiträge seit 2008
vor 12 Jahren

Der Thread ist nicht tot zu bekommen:

Erstmal danke für deinen Link.
Damit ich einmal zum Ende komme habe ich die ganze Sache nun händisch implementiert. Ich weise also die Werte manuell zu. Die Updateproblematik ist mir klar geworden, aber warum zwei Datensätze erstellt werden nicht wirklich.

Ich hoffe in den kommenden Versionen gibts in diesem Bereich noch Verbesserungen. An sich ist das Binding ja eine tolle Sache.

16.842 Beiträge seit 2008
vor 12 Jahren

Also ich hab durch den Fix des Binding Graphen das Phänomen des doppelten Eintrags lösen können. Taucht nirgends mehr auf, auch nicht mit UpdateModel.

I
itstata Themenstarter:in
302 Beiträge seit 2008
vor 12 Jahren

Ich werd das Phänomen beobachten 😃