插入/更新多对多实体框架。我该怎么做?
Posted
技术标签:
【中文标题】插入/更新多对多实体框架。我该怎么做?【英文标题】:Insert/Update Many to Many Entity Framework . How do I do it? 【发布时间】:2011-05-14 06:45:49 【问题描述】:我正在使用 EF4 并且是新手。我的项目中有很多对很多,似乎无法弄清楚如何插入或更新。我建立了一个小项目,只是为了看看它应该如何编码。
假设我有 3 张桌子
-
类:ClassID-ClassName
学生:StudentID-FirstName-Surname
StudentClass : StudentID-ClassID
通过模型浏览器添加所有关系并更新模型后,我注意到 StudentClass 没有出现,这似乎是默认行为。
现在我需要同时进行插入和更新。你怎么做呢?我可以下载示例的任何代码示例或链接,或者您能抽出 5 分钟吗?
【问题讨论】:
【参考方案1】:就实体(或对象)而言,您有一个 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();
由于两个学生都已在数据库中,因此不会插入他们,但由于他们现在位于 Class
的 Students
集合中,因此将在 StudentClass
表中插入两个条目。
【讨论】:
嗨,谢谢您的回复。我的情况是我需要在班级中插入 1 个条目,并且作为 x 您的示例 2 个条目进入 StudentClass 而没有进入 Student。我很困惑我该怎么做那 那是一种享受。关于更新。我需要做什么特别的事情吗?例如。只是更新类名。 这将增加从数据库中获取需要添加的项目的开销。 Attach 方法可用于仅添加关系。见msdn.microsoft.com/en-us/data/jj592676.aspx 和***.com/questions/11355019/… AddToClasses 是 Class 的 DbSet? 不要忘记在 Class 和 Student 的构造函数中初始化您的集合。例如: public Class() this.Students = new HashSet在实体框架中,当对象被添加到上下文中时,其状态变为已添加。 EF 还会更改每个对象的状态以添加到对象树中,因此您要么收到主键违规错误,要么在表中添加重复记录。
【讨论】:
【参考方案3】:试试这个更新:
[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) 来处理它。 考虑到问题是插入和更新,这个答案完成了问题和接受的答案。非常感谢! 所以 mathClassModel 有 2 个集合,Student 有它的实体,SelectedStudents 只有它的 ID,为什么?当您只有一个 ChildId 和 Child 实体时,Entity Framework 是否会自动映射它们?我不这么认为【参考方案4】:我想补充一下我的经验。实际上 EF,当您将对象添加到上下文时,它会将所有子对象和相关实体的状态更改为已添加。尽管这里的规则有一个小例外:如果子/相关实体被相同的上下文跟踪,EF 确实知道这些实体存在并且不会添加它们。例如,当您从其他上下文或 Web ui 等加载子实体/相关实体时,就会出现问题,然后是的,EF 对这些实体一无所知,然后去添加所有实体。为避免这种情况,只需获取实体的键并找到它们(例如,context.Students.FirstOrDefault(s => s.Name == "Alice"))
在您想要添加的相同上下文中。
【讨论】:
【参考方案5】:我使用下面的方式来处理只涉及外键的多对多关系。
所以对于插入:
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();
【讨论】:
以上是关于插入/更新多对多实体框架。我该怎么做?的主要内容,如果未能解决你的问题,请参考以下文章