插入/更新多对多实体框架。我该怎么做?

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

由于两个学生都已在数据库中,因此不会插入他们,但由于他们现在位于 ClassStudents 集合中,因此将在 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(); 【参考方案2】:

在实体框架中,当对象被添加到上下文中时,其状态变为已添加。 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 =&gt; 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();
        
    

【讨论】:

以上是关于插入/更新多对多实体框架。我该怎么做?的主要内容,如果未能解决你的问题,请参考以下文章

多对多实体框架和存储库模式插入/更新

在不使用实体框架的多对多中插入记录

具有存储库模式的实体框架,将数据插入到具有多对多关系的表中

多对多(自相关)特定订单实体框架

CoreData 多对多关系

删除多对多实体框架