在 POST 方法中从 ViewModel 检索数据

Retrieving data from a ViewModel in POST method

我有一个像这样的视图模型

 public class ItemViewModel
    {
        [Required]
        public int Id { get; set; }
        public string ItemId { get; set; }
        public string ItemName { get; set; }
        public string MFGNumber { get; set; }
        public IList<ItemPartViewModel> Parts { get; set; }
        public IList<ItemComponentViewModel> Components{ get; set; }
        public IList<ComponentPartViewModel> ComponentParts { get; set; }
        public IList<ComponentSubCompViewModel> ComponentSubComps { get; set; }
        public IList<SubCompPartViewModel> SubCompParts { get; set; }
        public IList<SubCompSubCompViewModel> SubCompSubComps { get; set; }
        public IList<SubCompSubCompPartViewModel> SubCompSubCompParts { get; set; }
    }

如您所见,Viewmodel 也有相应的视图模型,如下所示

public class ItemPartViewModel
    {
        [Required]
        public int ID { get; set; }
        public string PartID { get; set; }
        public HtmlString PartLink { get; set; }
        public string MFGNumber { get; set; }
        public string PartName { get; set; }
        public float QtyInItem { get; set; }
        public float OnHand { get; set; }
        public float OnWorkOrder { get; set; }
        public float Committed { get; set; }
        public float FSTK { get; set; }

        // This is the additional property to contain what user picks
        public PartActionType SelectedActionType { get; set; }
    }

ItemViewModel 是通过我的 OrderSelection GET 方法填充的,如下所示

 public ActionResult SpecialOrderSelection(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }

            JobOrder jobOrder = db.JobOrders.Find(id);
            if (jobOrder == null)
            {
                return HttpNotFound();
            }
            ViewBag.JobOrderID = jobOrder.ID;
            ItemInstance ii = db.ItemInstances.Where(x => x.serialNumber == jobOrder.serialNumber).FirstOrDefault();
            Item item = db.Items.Find(ii.ItemID);

            var vm = new ItemViewModel
            {
                Id = item.ID,
                ItemId = item.ItemID,
                ItemName = item.Name,
                Parts = new List<ItemPartViewModel>(),
                Components = new List<ItemComponentViewModel>(),
                ComponentParts = new List<ComponentPartViewModel>(),
                ComponentSubComps = new List<ComponentSubCompViewModel>(),
                SubCompParts = new List<SubCompPartViewModel>(),
                SubCompSubComps = new List<SubCompSubCompViewModel>(),
                SubCompSubCompParts = new List<SubCompSubCompPartViewModel>()
            };

            foreach (ItemHasParts ihp in item.IHP)
            {
                Part part = db.Parts.Find(ihp.PartID);
               

                vm.Parts.Add(new ItemPartViewModel
                {
                    ID = part.ID,
                    PartID = part.PartID,
                    PartLink = part.PartIDLink,
                    MFGNumber = part.MFG_number,
                    QtyInItem = ihp.qty,
                    OnHand = part.On_Hand,
                    OnWorkOrder = part.On_Order_Count(true, true),
                    Committed = part.CommittedCount(true, true),
                    FSTK = part.FSTK,
                    PartName = part.Name,
                    SelectedActionType = PartActionType.Transfer
                });
            }

    return View(vm);
}

然后数据会正确显示在 selection 页面上。但在此页面上,用户必须 select 是否要 harvest/transfer/or 处置零件。因此,一旦用户完成 select 选项,他们就会点击 'submit' 按钮。这个然后POSTS到这个方法

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult SpecialOrderSelection(ItemViewModel model)
        {
            //list of transfers
            //list of harvests
            //list of disposals      
            if (ModelState.IsValid)
            {
                JobOrder jobOrder = db.JobOrders.Find(model.Id);
                if (jobOrder == null)
                {
                    return HttpNotFound();
                }
                ViewBag.JobOrderID = jobOrder.ID;
                // do whatever with 'model' and return or redirect to a View
            }

            //ViewBag.submitted = true;
            return RedirectToAction("SpecialOrderSummary", new { ID = jobOrder.ID });   

        }

这里的问题是对于每个列表,(Parts/Components/ComponentParts/etc.) ID 为空。为什么它在 POST 而不是 GET 上为空?我该如何解决这个问题,使其不为空

这是我的视图的开头

 @using (Html.BeginForm())
    {
        @Html.AntiForgeryToken()
        @Html.HiddenFor(model => model.Id)
        <div class="form-horizontal">

            <h2 class="noprint">Special Order Selection</h2>
            <p style="color:red" class="noprint">Please select what is to be done with each component/part</p>

            <td align="left">


                <hr class="noprint" />
                <h4 class="noprint"><b>Work Order ID:</b> @Html.DisplayFor(model => j.ID)</h4>
                <br class="noprint" />

这是它的有效载荷

<form action="/JODetails/SpecialOrderSelection/3092" method="post"><input name="__RequestVerificationToken" type="hidden" value="LETTERSANDNUMBERS" /><input data-val="true" data-val-number="The field Id must be a number." data-val-required="The Id field is required." id="Id" name="Id" type="hidden" value="3092" />        <div class="form-horizontal">

            <h2 class="noprint">Special Order Selection</h2>
            <p style="color:red" class="noprint">Please select what is to be done with each component/part</p>

这是我的 'parts' 列表中的 'Part' 返回的示例

您在表单中的隐藏字段是 Id,这是 Model.Id (ItemViewModel) 而不是部分!然而,您在 POST 上检查的 属性 是 ID(即零件 ID)。您正在查找项目部件 ID,但表单中只有 ItemViewModel ID。由于您对项目部件属性有其他值,因此您必须在表单中某处迭代该部件列表。在此处为零件 ID 添加隐藏输入。

@{
  foreach(var part in Model.Parts) {
     @Html.HiddenFor(model => part.ID)
  }
}