Вставити / оновити багато-багато суб'єктів господарювання. Як це зробити?


104

Я використовую EF4 та новий для нього. У моєму проекті є багато-багато, і, здається, не виходить, як вставити чи оновити. Я створив невеликий проект лише для того, щоб побачити, як його слід закодувати.

Припустимо, у мене є 3 таблиці

  1. Клас: ClassID-ClassName
  2. Студент: StudentID-FirstName-прізвище
  3. StudentClass: StudentID-ClassID

Після додавання всіх взаємозв'язків та оновлення моделі через браузер моделі я помітив, що StudentClass не з'являється, це, здається, поведінка за замовчуванням.

Тепер мені потрібно зробити як Insert, так і Update. Як ти це робиш? Будь-які зразки коду чи посилання, де я можу завантажити приклад, або ви можете зекономити 5 хвилин?

Відповіді:


139

З точки зору сутностей (або об'єктів) у вас є 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 запис у клас, а як x ваш приклад 2 записи в StudentClass і жоден запис у Student. Я збентежений, як це зробити
user9969

ЩО РОБОТИ ДОПОМОГУ. Зважаючи на оновлення. Що-небудь особливе, що мені потрібно зробити? EG. Просто оновлення className, наприклад.
user9969

3
Це додасть накладні вилучення з бази даних елементів, які потрібно додати. Метод Attach можна використовувати лише для додавання відношення. Див msdn.microsoft.com/en-us/data/jj592676.aspx , а також stackoverflow.com/questions/11355019 / ...
Gnomo

3
AddToClasses - це DbSet для класу?
Jo Smo

1
Не забудьте ініціалізувати свої колекції у конструкторах для класу та учня. Наприклад: public Class () {this.Students = new HashSet <Student> (); }
користувач1040323

40

Спробуйте це для оновлення:

[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, щось подібне до моєї сутності не існувало в контексті. Я щойно закликав контекст.MyEntityCollection.Attach (myEntity) для вирішення цього питання.
Кілазур

Ніколи б не зрозумів цього. Дякую тонну.
Пляж Джаред

1
Дозвольте мені тут подякувати. Я написав і протестував понад 130 рядків коду протягом останніх 4 днів, намагаючись виконати це завдання, але не зміг цього зробити. Спробував це, і справи працювали чудово. Хоча я не розумію мету встановлення змінної елемента, а потім взагалі не використовую її, я просто радий, що це працює! Дякую мільйон мільйонів !!!! :)
Чувак-Дастік

Враховуючи питання "Вставити та оновити", ця відповідь завершує питання та прийняту відповідь. Велике спасибі!
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();
        }
    }
}

1

У рамках сутності, коли об’єкт додається в контекст, його стан змінюється на Додано. EF також змінює стан кожного об'єкта, доданий у дереві об'єктів, і, отже, ви отримуєте помилку порушення первинного ключа або дублюючі записи додаються в таблицю.


2
Будь ласка, відредагуйте, щоб дати достатню кількість деталей, щоб користувачеві не потрібно було відвідувати ваш блог, щоб отримати відповідь.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.