使用 ASP.NET Core MVC MultiSelectList 更新多对多实体
Update many-to-many entity with ASP.NET Core MVC MultiSelectList
我有一个表单,我想在其中更新与另一个实体具有多对多关系的实体,并且我正在尝试使用 select
标记来创建 MultiSelectList
控制。我正在使用 ASP.NET Core 1.0 和 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
进入Edit
的HttpPost
变体时,两个属性都是null
。为什么在进入 Edit
函数之前清除视图模型中的属性?我已确认它们在 HttpGet
变体中设置正确,并且数据在视图中正确显示。
问题 2
由于进入 Edit
的数据无效,我无法测试我的数据库更新。我从 SelectList
中获取所选项目和从 Student.Courses
中获取 adding/removing 项目的方法是否正确?我找不到很多关于 EF Core 中多对多关系的文档。
我是 ASP.NET 和 Entity Framework 的新手,所以任何提示或批评都将不胜感激。
您不能将 <select>
绑定到复杂对象的集合(这就是 MultiSelectList
的含义。<select multiple>
元素回传其选定选项值的数组(在你的案例将是课程 Id
值的数组。你的模型需要一个 属性 来绑定。假设他 Id
属性 of Course
是 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
的值将包含您在视图中选择的课程 Id
值的数组。
我有一个表单,我想在其中更新与另一个实体具有多对多关系的实体,并且我正在尝试使用 select
标记来创建 MultiSelectList
控制。我正在使用 ASP.NET Core 1.0 和 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
进入Edit
的HttpPost
变体时,两个属性都是null
。为什么在进入 Edit
函数之前清除视图模型中的属性?我已确认它们在 HttpGet
变体中设置正确,并且数据在视图中正确显示。
问题 2
由于进入 Edit
的数据无效,我无法测试我的数据库更新。我从 SelectList
中获取所选项目和从 Student.Courses
中获取 adding/removing 项目的方法是否正确?我找不到很多关于 EF Core 中多对多关系的文档。
我是 ASP.NET 和 Entity Framework 的新手,所以任何提示或批评都将不胜感激。
您不能将 <select>
绑定到复杂对象的集合(这就是 MultiSelectList
的含义。<select multiple>
元素回传其选定选项值的数组(在你的案例将是课程 Id
值的数组。你的模型需要一个 属性 来绑定。假设他 Id
属性 of Course
是 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
的值将包含您在视图中选择的课程 Id
值的数组。