Einfügen / Aktualisieren von Many to Many Entity Framework. Wie mache ich es?


104

Ich benutze EF4 und neu darin. Ich habe viele zu viele in meinem Projekt und kann anscheinend nicht herausfinden, wie man sie einfügt oder aktualisiert. Ich habe ein kleines Projekt erstellt, um zu sehen, wie es codiert werden soll.

Angenommen, ich habe 3 Tabellen

  1. Klasse: ClassID-ClassName
  2. Student: StudentID-Vorname-Nachname
  3. StudentClass: StudentID-ClassID

Nachdem ich die gesamte Beziehung hinzugefügt und das Modell über den Modellbrowser aktualisiert habe, habe ich festgestellt, dass StudentClass nicht angezeigt wird. Dies scheint ein Standardverhalten zu sein.

Jetzt muss ich sowohl ein Einfügen als auch ein Update durchführen. Wie machst du das? Irgendwelche Codebeispiele oder Links, über die ich ein Beispiel herunterladen kann, oder können Sie 5 Minuten sparen?

Antworten:


139

In Bezug auf Entitäten (oder Objekte) haben Sie ein ClassObjekt mit einer Sammlung von Studentsund ein StudentObjekt mit einer Sammlung von Classes. Da Ihre StudentClassTabelle nur die IDs und keine zusätzlichen Informationen enthält, generiert EF keine Entität für die Verknüpfungstabelle. Das ist das richtige Verhalten und das erwarten Sie.

Versuchen Sie nun beim Einfügen oder Aktualisieren, in Objekten zu denken. Wenn Sie beispielsweise eine Klasse mit zwei Schülern einfügen möchten, erstellen Sie das ClassObjekt, die StudentObjekte, fügen Sie die Schüler zur Klassensammlung hinzu Students, fügen Sie das ClassObjekt zum Kontext hinzu und rufen Sie auf SaveChanges:

using (var context = new YourContext())
{
    var mathClass = new Class { Name = "Math" };
    mathClass.Students.Add(new Student { Name = "Alice" });
    mathClass.Students.Add(new Student { Name = "Bob" });

    context.AddToClasses(mathClass);
    context.SaveChanges();
}

Dadurch wird ein Eintrag in der ClassTabelle erstellt, zwei Einträge in der StudentTabelle und zwei Einträge in der StudentClassTabelle, die sie miteinander verbinden.

Grundsätzlich tun Sie dasselbe für Updates. Rufen Sie einfach die Daten ab, ändern Sie das Diagramm, indem Sie Objekte zu Sammlungen hinzufügen und daraus entfernen SaveChanges. Überprüfen Sie diese ähnliche Frage für Details.

Bearbeiten :

Gemäß Ihrem Kommentar müssen Sie eine neue einfügen Classund zwei vorhandene hinzufügen Students:

using (var context = new YourContext())
{
    var mathClass= new Class { Name = "Math" };
    Student student1 = context.Students.FirstOrDefault(s => s.Name == "Alice");
    Student student2 = context.Students.FirstOrDefault(s => s.Name == "Bob");
    mathClass.Students.Add(student1);
    mathClass.Students.Add(student2);

    context.AddToClasses(mathClass);
    context.SaveChanges();
}

Da sich beide Schüler bereits in der Datenbank befinden, werden sie nicht eingefügt. Da sie sich jedoch jetzt in der StudentsSammlung der befinden Class, werden zwei Einträge in die StudentClassTabelle eingefügt .


Hallo, danke für Ihre Antwort. Mein Szenario ist, dass ich 1 Eintrag in die Klasse und als x Ihr Beispiel 2 Einträge in die StudentClass und keinen Eintrag in Student einfügen muss. Ich bin verwirrt, wie ich das mache
user9969

DAS HAT EINEN BEHANDLUNG GEARBEITET. Bezüglich des Updates. Ist etwas Besonderes, das ich tun muss? ZB nur den Klassennamen aktualisieren.
user9969

3
Dies erhöht den Aufwand für das Abrufen der Elemente, die hinzugefügt werden müssen, aus der Datenbank. Mit der Attach-Methode kann nur eine Beziehung hinzugefügt werden. Siehe msdn.microsoft.com/en-us/data/jj592676.aspx und auch stackoverflow.com/questions/11355019/…
Gnomo

3
AddToClasses ist das DbSet für die Klasse?
Jo Smo

1
Vergessen Sie nicht, Ihre Sammlungen in den Konstruktoren für Class und Student zu initialisieren. Zum Beispiel: public Class () {this.Students = new HashSet <Student> (); }
user1040323

40

Versuchen Sie dies zum Aktualisieren:

[HttpPost]
public ActionResult Edit(Models.MathClass mathClassModel)
{
    //get current entry from db (db is context)
    var item = db.Entry<Models.MathClass>(mathClassModel);

    //change item state to modified
    item.State = System.Data.Entity.EntityState.Modified;

    //load existing items for ManyToMany collection
    item.Collection(i => i.Students).Load();

    //clear Student items          
    mathClassModel.Students.Clear();

    //add Toner items
    foreach (var studentId in mathClassModel.SelectedStudents)
    {
        var student = db.Student.Find(int.Parse(studentId));
        mathClassModel.Students.Add(student);
    }                

    if (ModelState.IsValid)
    {
       db.SaveChanges();
       return RedirectToAction("Index");
    }

    return View(mathClassModel);
}

das hat mir den tag gerettet danke !!! Der Schlüsselteil ist das Element. Sammlung (i => i.Students) .Load (); Teil
Gerrie Pretorius

Nur eine Randnotiz: Ich hatte dabei eine InvalidOperationException, so etwas wie meine Entität war im Kontext nicht vorhanden. Ich habe gerade context.MyEntityCollection.Attach (myEntity) aufgerufen, um damit umzugehen.
Kilazur

Hätte das nie herausgefunden. Danke vielmals.
Jared Beach

1
Gestatten Sie mir, hier meinen Dank hinzuzufügen. Ich habe in den letzten 4 Tagen über 130 Codezeilen geschrieben und getestet, um diese Aufgabe zu erfüllen, konnte es aber nicht. Versuchte dies und die Dinge funktionierten perfekt. Ich verstehe zwar nicht den Zweck, die Elementvariable einzurichten und sie dann überhaupt nicht zu verwenden, bin aber nur froh, dass sie funktioniert! Vielen Dank, eine Million Bajillion! :)
Dude-Dastic

Wenn man bedenkt, dass die Frage Einfügen UND Aktualisieren lautet, vervollständigt diese Antwort die Frage und die akzeptierte Antwort. Vielen Dank!
Vahx

5

Ich wollte meine Erfahrung dazu hinzufügen. In der Tat ändert EF beim Hinzufügen eines Objekts zum Kontext den Status aller untergeordneten und verwandten Entitäten in Hinzugefügt. Obwohl die Regel hier eine kleine Ausnahme enthält: Wenn die untergeordneten / verwandten Entitäten im selben Kontext verfolgt werden, versteht EF, dass diese Entitäten vorhanden sind, und fügt sie nicht hinzu. Das Problem tritt auf, wenn Sie beispielsweise die untergeordneten / verwandten Entitäten aus einem anderen Kontext oder einer Web-Benutzeroberfläche usw. laden und dann, ja, EF nichts über diese Entitäten weiß und alle hinzufügt. Um dies zu vermeiden, holen Sie sich einfach die Schlüssel der Entitäten und suchen Sie sie (z. B. context.Students.FirstOrDefault(s => s.Name == "Alice"))in demselben Kontext, in dem Sie die Addition durchführen möchten.


3

Ich verwende die folgende Methode, um die Viele-zu-Viele-Beziehung zu behandeln, bei der nur Fremdschlüssel beteiligt sind.

Also zum Einfügen :

public void InsertStudentClass (long studentId, long classId)
{
    using (var context = new DatabaseContext())
    {
        Student student = new Student { StudentID = studentId };
        context.Students.Add(student);
        context.Students.Attach(student);

        Class class = new Class { ClassID = classId };
        context.Classes.Add(class);
        context.Classes.Attach(class);

        student.Classes = new List<Class>();
        student.Classes.Add(class);

        context.SaveChanges();
    }
}

Zum Löschen ,

public void DeleteStudentClass(long studentId, long classId)
{
    Student student = context.Students.Include(x => x.Classes).Single(x => x.StudentID == studentId);

    using (var context = new DatabaseContext())
    {
        context.Students.Attach(student);
        Class classToDelete = student.Classes.Find(x => x.ClassID == classId);
        if (classToDelete != null)
        {
            student.Classes.Remove(classToDelete);
            context.SaveChanges();
        }
    }
}

1

Wenn im Entitätsframework ein Objekt zum Kontext hinzugefügt wird, ändert sich sein Status in Hinzugefügt. EF ändert auch den Status jedes Objekts, um es im Objektbaum hinzuzufügen. Daher wird entweder ein Fehler bei der Verletzung des Primärschlüssels angezeigt oder es werden doppelte Datensätze in die Tabelle aufgenommen.


2
Bitte bearbeiten Sie , um genügend Details anzugeben, damit ein Benutzer Ihr Blog nicht besuchen muss, um die Antwort zu erhalten.
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.