Вставить / обновить многие ко многим Entity Framework. Как мне это сделать?

104

Я использую EF4 и новичок в нем. В моем проекте много ко многим, и я не могу понять, как вставлять или обновлять. Я создал небольшой проект, чтобы посмотреть, как его следует кодировать.

Предположим, у меня есть 3 стола

  1. Класс: ClassID-ClassName
  2. Студент: StudentID-FirstName-Surname
  3. StudentClass: StudentID-ClassID

После добавления всех взаимосвязей и обновления модели через браузер модели я заметил, что StudentClass не отображается, похоже, это поведение по умолчанию.

Теперь мне нужно выполнить как вставку, так и обновление. Как ты это делаешь? Любые образцы кода или ссылка, по которой я могу скачать пример, или вы можете сэкономить 5 минут?

user9969
источник

Ответы:

140

С точки зрения сущностей (или объектов) у вас есть Classобъект, который имеет коллекцию, Studentsи Studentобъект, который имеет коллекцию Classes. Поскольку ваша StudentClassтаблица содержит только идентификаторы и не содержит дополнительной информации, EF не создает сущность для присоединяемой таблицы. Это правильное поведение, и этого вы ожидаете.

Теперь, выполняя вставки или обновления, попробуйте мыслить объектами. Например, если вы хотите вставить класс с двумя учениками, создайте Classобъект, Studentобъекты, добавьте учеников в Studentsколлекцию классов, добавьте Classобъект в контекст и вызовите 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();
}

Это создаст запись в Classтаблице, две записи в Studentтаблице и две записи в StudentClassтаблице, связывающие их вместе.

Вы в основном делаете то же самое для обновлений. Просто получите данные, измените график, добавив и удалив объекты из коллекций, вызовите SaveChanges. Проверьте этот же вопрос для деталей.

Редактировать :

Согласно вашему комментарию, вам нужно вставить новый Classи добавить 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();
}

Поскольку оба студента уже находятся в базе данных, они не будут вставлены, но поскольку они теперь находятся в Studentsколлекции Class, две записи будут вставлены в StudentClassтаблицу.

Якимыч
источник
Привет, спасибо за ваш ответ. Мой сценарий таков: мне нужно вставить 1 запись в класс и, как ваш пример, 2 записи в StudentClass и не входить в Student. Я не понимаю, как я это делаю
user9969
ЭТО Сработало ОБРАБОТКА. Что касается обновления. Что мне нужно сделать особенного? Например, просто обновить className.
user9969
3
Это добавит накладных расходов на выборку из базы данных элементов, которые необходимо добавить. Метод Attach можно использовать для добавления только отношения. См. Msdn.microsoft.com/en-us/data/jj592676.aspx, а также stackoverflow.com/questions/11355019/…
Gnomo
3
AddToClasses - это DbSet для класса?
Jo Smo
1
Не забудьте инициализировать свои коллекции в конструкторах Class и Student. Например: public Class () {this.Students = new HashSet <Student> (); }
user1040323
41

Попробуйте это для обновления:

[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);
}
Стритоф
источник
это спасло мне день, спасибо !!! их ключевой частью является item.Collection (i => i.Students) .Load (); часть
Джерри Преториус
Просто примечание: при этом у меня было исключение InvalidOperationException, что-то вроде моей сущности не существовало в контексте. Я просто позвонил context.MyEntityCollection.Attach (myEntity), чтобы разобраться с этим.
Kilazur 02 июл.15,
Никогда бы не понял этого. Благодаря тонну.
Джаред Бич,
1
Позвольте мне добавить сюда свою благодарность. Я написал и протестировал более 130 строк кода за последние 4 дня, пытаясь выполнить эту задачу, но не смог. Пробовал это, и все работало отлично. Хотя я не понимаю цели создания переменной элемента, а затем вообще не использовать ее, я просто рад, что это работает! Спасибо миллион баджиллион !!!! :)
Dude-Dastic
Учитывая, что вопрос вставлен и обновлен, этот ответ завершает вопрос и принятый ответ. Большое спасибо!
Vahx
5

Я хотел добавить к этому свой опыт. Действительно, EF, когда вы добавляете объект в контекст, он изменяет состояние всех дочерних и связанных сущностей на «Добавлено». Хотя в этом правиле есть небольшое исключение: если дочерние / связанные сущности отслеживаются одним и тем же контекстом, EF понимает, что эти сущности существуют, и не добавляет их. Проблема возникает, когда, например, вы загружаете дочерние / связанные объекты из какого-либо другого контекста или веб-интерфейса и т.д., а затем да, EF ничего не знает об этих объектах и ​​идет и добавляет их все. Чтобы этого избежать, просто возьмите ключи сущностей и найдите их (например, context.Students.FirstOrDefault(s => s.Name == "Alice"))в том же контексте, в котором вы хотите выполнить добавление.

Афина
источник
3

Я использую следующий способ обработки отношения «многие ко многим», в котором задействованы только внешние ключи.

Итак, для вставки :

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

Для удаления ,

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();
        }
    }
}
lenglei
источник
1

В структуре сущностей, когда объект добавляется в контекст, его состояние изменяется на Добавлен. EF также изменяет состояние каждого объекта, добавляемого в дерево объектов, и, следовательно, вы либо получаете ошибку нарушения первичного ключа, либо повторяющиеся записи добавляются в таблицу.

Нилеш Хирапра
источник
2
Пожалуйста, отредактируйте, чтобы предоставить достаточно информации, чтобы пользователю не приходилось посещать ваш блог, чтобы получить ответ.