使用ASP.NET Core MVC MultiSelectList更新多對多實體

asp.net-core-1.0 asp.net-mvc c# entity-framework-core

我有一個表單,我想更新一個與另一個實體有多對多關係的實體,我正在嘗試使用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進入EditHttpPost變體時,兩個屬性都為null 。為什麼在進入Edit功能之前,視圖模型中的屬性會被清除?我已經確認它們在HttpGet變體中設置正確,並且數據在視圖中正確顯示。

問題2

由於進入Edit的數據無效,我無法測試我的數據庫更新。我的方法是從SelectList中獲取所選項目並在Student.Courses添加/刪除項目是否正確?我無法在EF Core中找到很多關於多對多關係的文檔。

我是ASP.NET和實體框架的新手,所以任何提示或批評都會非常感激。

一般承認的答案

您不能將<select>綁定到復雜對象的集合(這是MultiSelectList的集合。 <select multiple>元素回發其所選選項值的數組(在您的情況下將是Courses Id值的數組) 。您的模型需要綁定到一個屬性,假設他Id的財產Courseint ,然後添加以下屬性

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

另請注意,標記幫助程序會忽略在MultiSelectList構造函數中設置selectedValues屬性(在內部,該方法根據屬性的值構建新的IEnumerable<SelectListItem>方法中的代碼應該是

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值的數組。



Related

許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow