使用ASP更新多对多实体.. NET Core MVC MultiSelectList

本文关键字:Core MVC MultiSelectList NET ASP 更新 使用 实体 | 更新日期: 2023-09-27 18:04:09

我有一个表单,我想更新一个实体与另一个实体的多对多关系,我试图使用select标签来创建MultiSelectList控件。我用的是ASP。. NET Core 1.0 with Entity Framework.

假设我有以下实体:

public class Student
{
    public int Id { get; set; }
    public string Name { get; set; }
    public List<StudentCourse> Courses { get; set; }
}
public class Course
{
    public int Id { get; set; }
    public string Name { get; set; }
    public List<StudentCourse> Students { get; set; }
}
public class StudentCourse
{
    public int StudentId { get; set; }
    public Student Student { get; set; }
    public int CourseId { get; set; }
    public Course Course { get; set; }
}

视图模型:

public class StudentVM
{
    public Student Student { get; set; }
    public IEnumerable<SelectListItem> CourseList { get; set; }
}
视图:

@model StudentVM
<form asp-action="Edit">
    <div class="form-horizontal>
        <div class="form-group">
            <select asp-for="CourseList" asp-items="Model.CourseList" />
        </div>
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Save" class="btn btn-default" />
            </div>
        </div>
    </div>
</form>

控制器的动作方法:

[HttpGet]
public async Task<IActionResult> Edit(Student student)
{
    var viewmodel = new StudentVM {
        Student = student,
        CourseList = new MultiSelectList(
            _db.Courses,
            "Id",
            "Name",
            student.Courses
            .Select(sc => sc.CourseId));
    };
    return View(viewmodel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(StudentVM viewmodel)
{
    if (viewmodel.Student == null)
        return NotFound();
    if (ModelState.IsValid)
    {
        Student student = viewmodel.Student;
        var newCourses = viewmodel.CourseList
                         .Where(i => i.Selected)
                         .Select(c => new StudentCourse {
                             StudentId = student.Id,
                             CourseId = Convert.ToInt32(c.Value)
                         });
        student.Courses.RemoveAll(sc => !newCourses.Contains(sc));
        student.Courses.AddRange(
            newCourses.Where(nc => !student.Courses.Contains(nc)));
        _db.Update(student);
        _db.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(viewmodel);
}

现在是问题…

问题1

StudentVM进入EditHttpPost变体时,两者的性质都是null。为什么视图模型中的属性在进入Edit函数之前被清除?我已经确认它们在HttpGet变体中被正确设置,并且数据在视图中正确显示。

问题2

由于进入Edit的数据无效,我无法测试我的数据库更新。我从SelectList中获得选定项目并从Student.Courses中添加/删除项目的方法是否正确?我没能找到很多关于EF Core中多对多关系的文档。

我对ASP相当陌生。. NET和实体框架,所以任何提示或批评将非常感谢。

使用ASP更新多对多实体.. NET Core MVC MultiSelectList

您不能将<select>绑定到复杂对象的集合(这就是MultiSelectList)。<select multiple>元素返回它所选选项值的数组(在您的示例中是课程Id值的数组)。您的模型需要绑定到一个属性。假设CourseId属性为int,则添加以下属性

public IEnumerable<int> SelectedCourses { get; set; }

还要注意,在MultiSelectList构造函数中设置selectedValues属性会被标记帮助器忽略(该方法内部会根据该属性的值构建一个新的IEnumerable<SelectListItem>)。GET方法中的代码应该是

var viewmodel = new StudentVM
{
    Student = student,
    CourseList = new SelectList(_db.Courses, "Id", "Name"),
    SelectedCourses = student.Courses.Select(sc => sc.CourseId)   
};
return View(viewmodel);
然后在视图中使用
<select asp-for="SelectedCourses" asp-items="Model.CourseList"></select>

在POST方法中,SelectedCourses的值将包含您在视图中选择的Course Id值的数组