Insert / Update Many to Many Entity Framework. Jak to zrobić?

Używam EF4 i jestem w nim nowy. Mam wiele do wielu w moim projekcie i nie wiem, jak wstawić lub zaktualizować. Zbudowałem mały projekt, żeby zobaczyć, jak powinien być zakodowany.

Załóżmy, że mam 3 tabele

  1. Class: ClassID-ClassName
  2. Student: StudentID-Imię-Nazwisko
  3. StudentClass: StudentID-ClassID

Po dodaniu wszystkich relacji i zaktualizowaniu modelu za pomocą przeglądarki model zauważyłem, że StudentClass nie wydaje się, że jest to zachowanie domyślne.

Teraz muszę zrobić zarówno Insert jak i Update. Jak ty to robisz? Jakieś próbki kodu lub link, gdzie mogę pobrać przykład, czy możesz poświęcić 5 minut?

Author: abatishchev, 2010-11-23

5 answers

W kategoriach encji (lub obiektów) masz Class obiekt, który ma zbiór Students i Student obiekt, który ma zbiór Classes. Ponieważ twoja Tabela StudentClass zawiera tylko identyfikatory i nie zawiera dodatkowych informacji, EF nie generuje encji dla tabeli łączącej. To jest prawidłowe zachowanie i tego oczekujesz.

Teraz, podczas wstawiania lub aktualizacji, staraj się myśleć w kategoriach obiektów. Np. jeśli chcesz wstawić klasę z dwoma uczniami, Utwórz obiekt Class, Student obiekty, dodaj uczniów do kolekcji klasy Students Dodaj obiekt Class do kontekstu i wywołaj 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();
}

Spowoduje to utworzenie wpisu w tabeli Class, dwóch wpisów w tabeli Student i dwóch wpisów w tabeli StudentClass łączących je ze sobą.

Zasadniczo robisz to samo dla aktualizacji. Wystarczy pobrać dane, zmodyfikować Wykres dodając i usuwając obiekty ze zbiorów, wywołać SaveChanges. Sprawdź to podobne pytanie Dla szczegóły.

Edit :

Zgodnie z Twoim komentarzem, musisz wstawić nowy Class i dodać do niego dwa istniejące 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();
}

Ponieważ obaj uczniowie są już w bazie danych, nie zostaną wstawieni, ale ponieważ są teraz w kolekcji Students Class, dwa wpisy zostaną wstawione do Tabeli StudentClass.

 125
Author: Yakimych,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:43

Spróbuj tego do aktualizacji:

[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);
}
 36
Author: Stritof,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-22 13:54:55

Chciałem dodać moje doświadczenie na ten temat. Rzeczywiście, gdy dodajesz obiekt do kontekstu, zmienia on stan wszystkich dzieci i powiązanych podmiotów na dodany. Chociaż istnieje mały wyjątek w tej zasadzie: jeśli dzieci/podmioty powiązane są śledzone w tym samym kontekście, EF rozumie, że te podmioty istnieją i nie dodaje ich. Problem występuje, gdy na przykład ładujesz dzieci / powiązane podmioty z innego kontekstu lub web ui itp., a następnie tak, EF nic nie wie o tych bytach i dodaje je wszystkie. Aby tego uniknąć, po prostu pobierz klucze encji i znajdź je (np. context.Students.FirstOrDefault(s => s.Name == "Alice")) w tym samym kontekście, w którym chcesz dodać.

 4
Author: Athina,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-17 21:09:54

W ramach encji, gdy obiekt jest dodawany do kontekstu, jego stan zmienia się na Added. EF zmienia również stan każdego obiektu na dodany w drzewie obiektów i w związku z tym otrzymujesz błąd naruszenia klucza głównego lub dodawane są zduplikowane rekordy w tabeli.

 1
Author: Nilesh Hirapra,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-05 18:44:21

Używam następującego sposobu, aby obsłużyć relację wiele do wielu, w której zaangażowane są tylko klucze obce.

Więc dla wstawianie :

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();
    }
}

Dla ,

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
Author: tooatui,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-06 05:16:25