插入/更新多个到多个实体框架.我该怎么做?

use*_*969 101 c# many-to-many entity-framework

我正在使用EF4和它的新功能.我的项目中有很多对很多,似乎无法解决如何插入或更新.我已经构建了一个小项目,只是为了看它应该如何编码.

假设我有3个表

  1. 类:ClassID-ClassName
  2. 学生:StudentID-FirstName-Surname
  3. StudentClass:StudentID-ClassID

添加所有关系并通过模型浏览器更新模型后,我注意到StudentClass没有出现,这似乎是默认行为.

现在我需要同时进行插入和更新.你怎么做呢?我可以下载示例的任何代码示例或链接,还是可以节省5分钟?

Yak*_*ych 137

在实体(或对象)方面,您有一个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();
}
Run Code Online (Sandbox Code Playgroud)

这将在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();
}
Run Code Online (Sandbox Code Playgroud)

由于两个学生都已经在数据库中,因此不会插入它们,但由于它们现在位于其Students集合中,因此Class将在StudentClass表中插入两个条目.

  • 这将增加从数据库中获取需要添加的项目的开销.Attach方法可用于仅添加关系.请参阅http://msdn.microsoft.com/en-us/data/jj592676.aspx以及http://stackoverflow.com/questions/11355019/add-many-to-many-relation-without-fetching-child-实体从数据库 (3认同)
  • AddToClasses是Class的DbSet? (2认同)

Str*_*tof 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);
}
Run Code Online (Sandbox Code Playgroud)

  • 这正是更新所必须做的!谢谢 (2认同)

小智 5

我想补充一下我的经验。实际上,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();
    }
}
Run Code Online (Sandbox Code Playgroud)

对于删除

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)