[Entity Framework] Einträge werden ohne meinen Willen dupliziert

  • C#

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

    [Entity Framework] Einträge werden ohne meinen Willen dupliziert

    Hallo,

    ich verwende Entity Framework 6 und habe ein Problem:

    Ich habe eine Many to Many Beziehung zwischen Texte und Felder hergestellt, da verschiedene Texte mehrere Felder und umgekehrt haben kann.
    Außerdem gehört ein Feld immer zu einer Drucksorte.

    Wenn ich nun versuche einen Text zu speichern, dann wird die Drucksorte und auch alle Felder in der Datenbank dupliziert und die Felder werden der neuen Drucksorte zugeweisen.

    C#-Quellcode

    1. public class Drucksorte
    2. {
    3. public int Id { get; set; }
    4. public string Bezeichnung { get; set; }
    5. public virtual ICollection<Feld> Felder { get; set; }
    6. }
    7. public class Feld
    8. {
    9. public int Id { get; set; }
    10. public virtual Drucksorte Drucksorte { get; set; }
    11. public string Bezeichnung { get; set; }
    12. public virtual ICollection<Text> Texte { get; set; }
    13. public Feld()
    14. {
    15. this.Texte = new HashSet<Text>();
    16. }
    17. }
    18. public class Text
    19. {
    20. public int Id { get; set; }
    21. public string Bezeichnung { get; set; }
    22. public virtual ICollection<Feld> Felder { get; set; }
    23. public Text()
    24. {
    25. this.Felder = new HashSet<Feld>();
    26. }
    27. }
    28. private void button1_Click(object sender, EventArgs e)
    29. {
    30. Text text = new Text();
    31. text.bezeichnung = textBox1.text;
    32. foreach (object item in checkedListBox1.Items)
    33. {
    34. text.Felder.Add((Feld)item);
    35. }
    36. using (WFCDbContext db = new WFCDbContext())
    37. {
    38. db.Texte.Add(text);
    39. db.SaveChanges();
    40. }
    41. }
    Hallo

    Was soll denn sonst passieren. Mit .Add(text) fügst du ja ein Object ein.

    Willst du ein Object ändern ohne EF die Änderung explizit bekannt zu geben, sprich den entityState auf Changed zu setzen musst du den Context solange am leben erhalten bis du wieder gespeichert hast.
    Nur so kann der ChangeTracker von EF die Änderung mitbekommen (weil er dann ja dabei war) und dies anschliessend beim speichern wieder persistieren.

    also z.b.:

    C#-Quellcode

    1. private void button1_Click(object sender, EventArgs e)
    2. {
    3. using (WFCDbContext db = new WFCDbContext())
    4. {
    5. var currentText = db.Texte.Include(t => t.Felder).First();
    6. currentText.bezeichnung = textBox1.text;
    7. foreach (object item in checkedListBox1.Items)
    8. {
    9. currentText.Felder.Add((Feld)item);
    10. }
    11. bool successfully = db.SaveChanges() > 0;
    12. }
    13. }


    Habs jetzt nur aus dem Kopf geschrieben, bin ausserdem VBler, muss also Syntaktisch nicht ganz korrekt sein.

    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. ##

    Hmmm verstehe ich trotzdem nicht, ich verändere ja keine bestehende Entität?
    Ich erstelle ein neues Text Object füge diesem dann bestehende Felder hinzu und versuche das neu erstellte Text Object zu speichern.

    Ich habe zu keinem Zeitpunkt ein Feld oder eine Drucksorte verändert... ?

    So funktionierts auch nicht...

    C#-Quellcode

    1. using (WFCDbContext db = new WFCDbContext())
    2. {
    3. var newText = new Text();
    4. newText.bezeichnung = textBox1.text;
    5. foreach (object item in checkedListBox1.Items)
    6. {
    7. newText.Felder.Add((Feld)item);
    8. }
    9. db.Texte.Add(newText);
    10. db.SaveChanges();
    11. }

    Ahhh, jetzt verstehe ich was du machen willst.

    JA, dann müssen aber die Objekte aus der ListBox (Felder) von der selben Context-Instanz kommen.
    Also das befülen der ListBox muss aus der selben Contextinstanz passieren wie das hinzufügen und speichern.

    Sonst sieht EF die Felder (welche du aus der Listbox holst) als neue an. In dem Moment wo du sie dann dem Text.Felder Objekt hinzufügst geht der EntityState des Feldes auf Added anstatt das dieser auf UnChanged bleibt. So funktioniert der ChangeTracker.


    Also lass den Context offen. Du kannst ihn auch als Variable definieren und beim schliessen des Forms Disposen.
    Alternativ kannst du nur den EntityState jedes Feldes auf Unchanged setzen. Aber ich denke dann müsstest du die Rücknavigation dafür mit angeben.

    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. ##

    Habs gelöst danke!!!

    C#-Quellcode

    1. using (WFCDbContext db = new WFCDbContext())
    2. {
    3. foreach (Feld feld in text.Felder)
    4. {
    5. db.Entry(feld).State = EntityState.Unchanged;
    6. db.Entry(feld.Drucksorte).State = EntityState.Unchanged;
    7. }
    8. db.Texte.Add(text);
    9. db.SaveChanges();
    10. }
    Hallo

    Genau, wie ch geschrieben habe geht es auch so.
    Achtung bitte: So klappt es hald aber NUR wenn man in dem Form die Felder NICHT editieren kann. Sonst würde die änderung nicht mitgespeichert werden.

    Sei so gut, wenn ein Thema erledigt ist dann bitte dementsprechend markieren. Auch dein anderes Thema.

    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. ##