我正在使用EF4和新手。我的项目中有很多对很多,似乎无法解决如何插入或更新。我已经构建了一个小项目,只是为了看它应该如何编码。
假设我有3个表
添加所有关系并通过模型浏览器更新模型后,我注意到StudentClass没有出现,这似乎是默认行为。
现在我需要同时进行插入和更新。你怎么做呢?我可以下载示例的任何代码示例或链接,还是可以节省5分钟?
答案 0 :(得分:132)
就实体(或对象)而言,您有一个Class
对象,其中包含Students
和Student
对象的集合,其集合为Classes
。由于您的StudentClass
表仅包含ID并且没有额外信息,因此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
。查看this similar question了解详情。
修改强>:
根据您的评论,您需要插入新的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
的{{1}}集合中,因此将在{{1}中插入两个条目表格。
答案 1 :(得分:39)
尝试使用此更新:
[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);
}
答案 2 :(得分:4)
我想在此添加我的经验。实际上,当您将对象添加到上下文时,它会将所有子项和相关实体的状态更改为“已添加”。虽然规则中存在一个小例外:如果孩子/相关实体被相同的上下文跟踪,EF确实理解这些实体存在并且不添加它们。例如,当您从其他某个上下文或web ui等加载子/相关实体然后是,EF不知道有关这些实体的任何内容并且添加所有这些实体时,就会出现问题。为了避免这种情况,只需获取实体的密钥并找到它们(例如context.Students.FirstOrDefault(s => s.Name == "Alice"))
在您想要添加的相同上下文中。
答案 3 :(得分:2)
我使用以下方法来处理只涉及外键的多对多关系。
因此插入:
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();
}
}
}
答案 4 :(得分:1)
在实体框架中,当将对象添加到上下文时,其状态将更改为“已添加”。 EF还会更改要添加到对象树中的每个对象的状态,因此您要么获得主键冲突错误,要么在表中添加重复记录。