ASP.NET Core MVCを使用して多対多のエンティティを更新するMultiSelectList

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

質問

私は、エンティティを他のエンティティと多対多の関係で更新するフォームを持っており、 selectタグを使用してMultiSelectListコントロールを作成しようとしていselect 。私はEntity FrameworkでASP.NET Core 1.0を使用しています。

次のエンティティがあるとします。

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

StudentVMEditHttpPostバリアントに入ると、両方のプロパティがnull 。なぜ、 Edit機能に入る前に、ビューモデルのプロパティがクリアされるのですか? HttpGetバリアントで正しく設定されていること、およびデータがビューに正しく表示されていることを確認しました。

質問2

Edit入ったデータが無効であるため、データベースの更新をテストできません。 SelectListから選択したアイテムを取得し、 Student.Coursesアイテムを追加/削除する方法は正しいですか?私はEFコアの多対多関係に関する多くの文書を見つけることができませんでした。

私はむしろASP.NETとEntity Frameworkの新機能ですので、ヒントや批判は大いに感謝しています。

受け入れられた回答

<select>を複合オブジェクトのコレクションにバインドすることはできません(これはMultiSelectListMultiSelectListです)。 <select multiple>要素は、選択したオプション値の配列をMultiSelectListます(この場合、Courses Id値の配列になります) 。あなたのモデルは、彼と仮定。にバインドするプロパティを必要とするIdのプロパティCourseあるintは、次のプロパティを追加します。

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

また、 MultiSelectListコンストラクタでselectedValuesプロパティを設定すると、タグヘルパーによって無視されます(内部的には、プロパティの値に基づいて新しいIEnumerable<SelectListItem>メソッドが構築selectedValuesます) MultiSelectListメソッドのコードは、

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
このKBは合法ですか? はい、理由を学ぶ
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ