Insert/Update Many to Many Entity Framework . How do I do it?
Solution 1:
In terms of entities (or objects) you have a Class
object which has a collection of Students
and a Student
object that has a collection of Classes
. Since your StudentClass
table only contains the Ids and no extra information, EF does not generate an entity for the joining table. That is the correct behaviour and that's what you expect.
Now, when doing inserts or updates, try to think in terms of objects. E.g. if you want to insert a class with two students, create the Class
object, the Student
objects, add the students to the class Students
collection add the Class
object to the context and call 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();
}
This will create an entry in the Class
table, two entries in the Student
table and two entries in the StudentClass
table linking them together.
You basically do the same for updates. Just fetch the data, modify the graph by adding and removing objects from collections, call SaveChanges
. Check this similar question for details.
Edit:
According to your comment, you need to insert a new Class
and add two existing Students
to it:
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();
}
Since both students are already in the database, they won't be inserted, but since they are now in the Students
collection of the Class
, two entries will be inserted into the StudentClass
table.
Solution 2:
Try this one for Updating:
[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);
}
Solution 3:
I use the following way to handle the many-to-many relationship where only foreign keys are involved.
So for inserting:
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();
}
}
For deleting,
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();
}
}
}
Solution 4:
I wanted to add my experience on that. Indeed EF, when you add an object to the context, it changes the state of all the children and related entities to Added. Although there is a small exception in the rule here: if the children/related entities are being tracked by the same context, EF does understand that these entities exist and doesn't add them. The problem happens when for example, you load the children/related entities from some other context or a web ui etc and then yes, EF doesn't know anything about these entities and goes and adds all of them. To avoid that, just get the keys of the entities and find them (e.g. context.Students.FirstOrDefault(s => s.Name == "Alice"))
in the same context in which you want to do the addition.