实体框架多对多关系在添加关系之前添加“结束”项

时间:2011-11-18 17:41:07

标签: asp.net-mvc entity-framework

我使用常见的学生和课程场景设置了一个非常简单的实体框架数据库第一个项目。

  • 学生可以有很多课程
  • 一门课程可以有很多学生

我在数据库中设置了关系,EF为此创建了一个很好的多对多导航项。

问题当我向学生添加课程时,课程会重新添加到课程表中,然后将关系添加到数据库中,从而导致每个不断增加的重复课程数量< / p> 这让我疯了,不知道我可能做错了什么?

我的一些代码......

我已经在实体生成的上面创建了一个Partial类,这样我就可以有一个带有复选框的EditorTemplate,这将允许用户勾选要添加的课程

public partial class Course
{
    public bool isSelected { get; set; }
}

public partial class Course
{
    public Course()
    {
        this.Students = new HashSet<Student>();
    }

    public int CourseId { get; set; }
    public string CourseName { get; set; }

    public virtual ICollection<Student> Students { get; set; }
}

课程的编辑模板

@model University.Models.Course

<div>
    @Html.CheckBoxFor(m => m.isSelected)
    @Html.DisplayFor(m => m.CourseName)


    @Html.HiddenFor(m => m.CourseName)
    @Html.HiddenFor(m =>m.CourseId)
</div>

创建学生视图

@model University.Models.CreateStudentViewModel            
@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>Student</legend>            
        <div class="editor-label">
            @Html.LabelFor(model => model.student.Name)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.student.Name)
            @Html.ValidationMessageFor(model => model.student.Name)
        </div>    
        <div>        
            @Html.EditorFor(m=>m.courses)
        </div>
        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
}

页面的ViewModel

public class CreateStudentViewModel
{
    public Student student { get; set; }
    public ICollection<Course> courses { get; set; }
}

控制器

public ActionResult Create()
{
    CreateStudentViewModel vm = new CreateStudentViewModel();
    vm.courses = db.Courses.ToList();
    return View(vm);
} 
[HttpPost]
public ActionResult Create(CreateStudentViewModel model)
{
    if (ModelState.IsValid)
    {
        model.student.Courses = model.courses.Where(m => m.isSelected == true).ToList();
        db.Students.Add(model.student);
        db.SaveChanges();
        return RedirectToAction("Index");  
    }
    return View(model);
}

任何帮助我指向正确方向的人都会非常感激

1 个答案:

答案 0 :(得分:3)

在将学生添加到上下文之前,您必须所选课程附加到帖子操作中的上下文。否则,EF假定整个对象图 - 包括所有课程的学生 - 是 new ,并且必须插入到数据库中。通过附加(=将课程设置为Unchanged状态),您告诉EF您不希望将附加的课程作为新行插入,而只是在新学生和现有课程之间创建关系:

[HttpPost]
public ActionResult Create(CreateStudentViewModel model)
{
    if (ModelState.IsValid)
    {
        model.student.Courses =
            model.courses.Where(m => m.isSelected == true).ToList();

        foreach (var course in model.student.Courses)
            db.Courses.Attach(course);
        // now each course is in state Unchanged in the context

        db.Students.Add(model.student);
        // model.student is in state Added in the context
        // but the courses still have the state Unchanged.
        // Without the attach-loop above they would be in
        // state Added as well, which will create new courses
        // in the DB after SaveChanges

        db.SaveChanges();

        return RedirectToAction("Index");  
    }
    return View(model);
}