回答編集履歴

1 追記

SurferOnWww

SurferOnWww score 7449

2018/10/12 12:37  投稿

先のスレッドで紹介した以下の記事は読んでもらえたでしょうか?
コレクションのデータアノテーション検証
[http://surferonwww.info/BlogEngine/post/2014/09/01/validation-of-collection-data-during-model-binding-using-data-annotation.aspx](http://surferonwww.info/BlogEngine/post/2014/09/01/validation-of-collection-data-during-model-binding-using-data-annotation.aspx)
そこに書いてあるように、コレクションのモデルバインディングがうまく行われるようにするには、レンダリングされる html 要素の name 属性が連番のインデックスを含むようにします。
質問者さんのコードの「回答」で言うと、name="Details[i].QA_Ans" という形で、i は 0 から始まる連番にします。
あと、モデルに定義されているすべての項目の値が POST されるようにします。なので ```<td>@item.QA_No</td>``` というような形ではなく、EditorFor を使うか、@item.QA_No とか DisplayFor を使うのであれば HiddenFor を追加してください。
と、言葉で書くだけでは分からないと思いますので、あとでサンプルコードを書いてアップします。お待ちください。
と、言葉で書くだけでは分からないと思いますので、あとでサンプルコードを書いてアップします。お待ちください。
**【追記】**
以下、サンプルです。
**Controller / Action Method / Model**
```
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.ComponentModel.DataAnnotations;
namespace Mvc5App.Controllers
{
   public class HomeController : Controller
   {
       public ActionResult Index()
       {
           return View();
       }
       [HttpGet]
       public ActionResult QuestionsAndAnswers()
       {
           // サンプル用の QAModels を作成
           QAModels model = new QAModels
           {
               QA_Id = 1,
               Employee_Id = 12345,
               Remarks = "備考",
               Details = new List<QADetailModels>
               {
                   // 質問数は任意。ここではとりあえず 5 題としています。
                   new QADetailModels { QA_Id = 1, Employee_Id = 12345, QA_No = 1, QA_Description = "質問文その 1" },
                   new QADetailModels { QA_Id = 1, Employee_Id = 12345, QA_No = 2, QA_Description = "質問文その 2" },
                   new QADetailModels { QA_Id = 1, Employee_Id = 12345, QA_No = 3, QA_Description = "質問文その 3" },
                   new QADetailModels { QA_Id = 1, Employee_Id = 12345, QA_No = 4, QA_Description = "質問文その 4" },
                   new QADetailModels { QA_Id = 1, Employee_Id = 12345, QA_No = 5, QA_Description = "質問文その 5" }
               }
           };
           return View(model);
       }
       [HttpPost]
       [ValidateAntiForgeryToken]
       public ActionResult QuestionsAndAnswers(QAModels model)
       {
           return View(model);
       }
   }
   // Model
   // Controller に含めたのは単に分けるのが面倒だったからです
   // 質問者さんのコードの DisplayName は古いので以下のように変えました
   // それ以外は質問者さんのコードの通りです。
   public class QAModels
   {
       [Display(Name="ID")]
       public int QA_Id { get; set; }
       [Display(Name="社員番号")]
       public int Employee_Id { get; set; }
       [Display(Name="備考")]
       public string Remarks { get; set; }
       public IList<QADetailModels> Details { get; set; }
   }
   public class QADetailModels
   {
       [Display(Name="ID")]
       public int QA_Id { get; set; }
       [Display(Name="社員番号")]
       public int Employee_Id { get; set; }
       [Display(Name="アンケートNo")]
       public short QA_No { get; set; }
       // このアンケート内容は別のテーブルから引いてくるものとする
       [Display(Name="アンケート内容")]
       public string QA_Description { get; set; }
       [Display(Name="回答")]
       public short QA_Ans { get; set; }
   }
}
```
**View**
上のアクションメソッド QuestionsAndAnswers をベースに Visual Studio 2015 のスキャフォールディング機能を使って自動生成させたものです。Template は Create を、Model class は QAModels を設定。それに <table> ... </table> のコードを追加した以外は手を加えていません。
```
@model Mvc5App.Controllers.QAModels
@{
   ViewBag.Title = "QuesttionsAndAnswers";
   Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>QuesttionsAndAnswers</h2>
@using (Html.BeginForm())
{
   @Html.AntiForgeryToken()
   
   <div class="form-horizontal">
       <h4>QAModels</h4>
       <hr />
       @Html.ValidationSummary(true, "", new { @class = "text-danger" })
       <div class="form-group">
           @Html.LabelFor(model => model.QA_Id, htmlAttributes: new { @class = "control-label col-md-2" })
           <div class="col-md-10">
               @Html.EditorFor(model => model.QA_Id, new { htmlAttributes = new { @class = "form-control" } })
               @Html.ValidationMessageFor(model => model.QA_Id, "", new { @class = "text-danger" })
           </div>
       </div>
       <div class="form-group">
           @Html.LabelFor(model => model.Employee_Id, htmlAttributes: new { @class = "control-label col-md-2" })
           <div class="col-md-10">
               @Html.EditorFor(model => model.Employee_Id, new { htmlAttributes = new { @class = "form-control" } })
               @Html.ValidationMessageFor(model => model.Employee_Id, "", new { @class = "text-danger" })
           </div>
       </div>
       <div class="form-group">
           @Html.LabelFor(model => model.Remarks, htmlAttributes: new { @class = "control-label col-md-2" })
           <div class="col-md-10">
               @Html.EditorFor(model => model.Remarks, new { htmlAttributes = new { @class = "form-control" } })
               @Html.ValidationMessageFor(model => model.Remarks, "", new { @class = "text-danger" })
           </div>
       </div>
       <table class="table">
           <tr>
               <th>
                   @Html.DisplayNameFor(model => model.Details[0].QA_No)
               </th>
               <th>
                   @Html.DisplayNameFor(model => model.Details[0].QA_Description)
               </th>
               <th>
                   @Html.DisplayNameFor(model => model.Details[0].QA_Ans)
               </th>
           </tr>
           @for (int i = 0; i < Model.Details.Count; i++)
           {
           <tr>
               @Html.HiddenFor(model => model.Details[i].QA_Id)
               @Html.HiddenFor(model => model.Details[i].Employee_Id)
               <td>                   
                   @Html.EditorFor(model => model.Details[i].QA_No, new { htmlAttributes = new { @class = "form-control" } })
               </td>
               <td>
                   @Html.EditorFor(model => model.Details[i].QA_Description, new { htmlAttributes = new { @class = "form-control" } })
               </td>
               <td>
                   @*@Html.EditorFor(model => model.Details[i].QA_Ans, new { htmlAttributes = new { @class = "form-control" } })*@
                   @Html.RadioButton("Details[" + i + "].QA_Ans", 5, false)<label>非常に満足 </label>
                   @Html.RadioButton("Details[" + i + "].QA_Ans", 4, false)<label>満足 </label>
                   @Html.RadioButton("Details[" + i + "].QA_Ans", 3, false)<label>普通 </label>
                   @Html.RadioButton("Details[" + i + "].QA_Ans", 2, false)<label>不満 </label>
                   @Html.RadioButton("Details[" + i + "].QA_Ans", 1, false)<label>非常に不満 </label>
               </td>
           </tr>
           }
       </table>
           <div class="form-group">
               <div class="col-md-offset-2 col-md-10">
                   <input type="submit" value="Create" class="btn btn-default" />
               </div>
           </div>
</div>
}
<div>
   @Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
   @Scripts.Render("~/bundles/jqueryval")
}
```
以下のように RadioButton を設定して[Create]ボタンをクリックするとデータがサーバーに送信されて、
![イメージ説明](d3c55cb7f41ca21a6b195be9ac42008c.jpeg)
以下の通り public ActionResult QuestionsAndAnswers(QAModels model) の model にモデルバインディングされます。
![イメージ説明](d03e7da7c2cfce4d1109ff7458e2f21c.jpeg)
以上ですが、分からないところがあったら聞いてください。

思考するエンジニアのためのQ&Aサイト「teratail」について詳しく知る