提交表单时模型集合丢失

使用下面的post请求,模型为两个集合返回null,但它正确返回boolean属性。 我的期望是在get请求期间加载到模型中的集合将持久保存到post请求。 我错过了什么?

编辑:基本上我试图根据用户选择的选择列表和复选框更新发票列表。

控制器:

[HttpGet] [AllowAnonymous] public async Task Index(bool displayFalse = true) { InvoiceViewModel invoiceView = new InvoiceViewModel(); var companies = new SelectList(await DbContext.Company.ToListAsync(), "CompanyID", "Name").ToList(); var invoices = await DbContext.Invoice.Where(s => s.Paid.Equals(displayFalse)).ToListAsync(); return View(new InvoiceViewModel { Companies = companies,Invoices = invoices, SelectedCompanyID = 0, DisplayPaid = displayFalse}); } [HttpPost] [AllowAnonymous] public async Task Index(InvoiceViewModel model) { model.Invoices = await DbContext.Invoice.Where(s => s.CompanyID.Equals(model.SelectedCompanyID) && s.Paid.Equals(model.DisplayPaid)).ToListAsync(); return View(model); } 

模型:

 public class InvoiceViewModel { public int SelectedCompanyID { get; set; } public bool DisplayPaid { get; set; } public ICollection Companies { get; set; } public ICollection Invoices{ get; set; } } 

视图:

 @model InvoiceIT.Models.InvoiceViewModel 

@foreach (var item in Model.Invoices) { }
@Html.DisplayNameFor(model => model.Invoices.FirstOrDefault().InvoiceID) @Html.DisplayNameFor(model => model.Invoices.FirstOrDefault().CompanyID) @Html.DisplayNameFor(model => model.Invoices.FirstOrDefault().Description) @Html.DisplayNameFor(model => model.Invoices.FirstOrDefault().InvoiceDate) @Html.DisplayNameFor(model => model.Invoices.FirstOrDefault().DueDate) @Html.DisplayNameFor(model => model.Invoices.FirstOrDefault().Paid)
@Html.DisplayFor(modelItem => item.InvoiceID) @Html.DisplayFor(modelItem => item.CompanyID) @Html.DisplayFor(modelItem => item.Description) @Html.DisplayFor(modelItem => item.InvoiceDate) @Html.DisplayFor(modelItem => item.DueDate) @Html.DisplayFor(modelItem => item.Paid) @Html.ActionLink("Edit", "Edit", new { id = item.InvoiceID }) | @Html.ActionLink("Details", "Index", "InvoiceItem", new { id = item.InvoiceID }) | @Html.ActionLink("Delete", "Delete", new { id = item.InvoiceID })

表单仅回发其控件的名称/值对(input,textarea,select)。 由于您生成的唯一2个控件是针对模型的SelectedCompanyIDDisplayPaid属性,因此在发布时仅绑定那些属性。

根据您的评论,您真正想要做的是根据所选公司的价值和复选框更新发票表。

从性能的角度来看,该方法是使用ajax根据控件的值更新发票表。

创建一个新的控制器方法,返回表行的部分视图

 public PartialViewResult Invoices(int CompanyID, bool DisplayPaid) { // Get the filtered collection IEnumerable model = DbContext.Invoice.Where(.... return PartialView("_Invoices", model); } 

请注意,如果您希望最初显示未过滤的结果,则可能需要使CompanyID参数为可空,并调整查询

并部分查看_Invoices.cshtml

 @model IEnumerable @foreach(var item in Model) {  @Html.DisplayFor(m => item.InvoiceID) .... other table cells  } 

在主视图中

 @model yourAssembly.InvoiceViewModel @Html.BeginForm()) // form may not be necessary if you don't have validation attributes { @Html.DropDownListFor(m => m.SelectedCompanyID, Model.Companies) @Html.CheckboxFor(m => m.DisplayPaid)  }  ....  // If you want to initially display some rows @Html.Action("Invoices", new { CompanyID = someValue, DisplayPaid = someValue }) 

另一种方法是将表单发布为您的表单,但不是返回视图,而是使用

 return RedirectToAction("Invoice", new { companyID = model.SelectedCompanyID, DisplayPaid = model.DisplayPaid }); 

并修改GET方法以接受附加参数。

附注:您使用TagHelpers生成

 select asp-for="SelectedCompanyID" asp-items="Model.Companies" name="companyFilter" class="form-control"> 

我不太熟悉它们,但是如果name="companyFilter"工作(并覆盖默认名称name="SelectedCompanyID" ),那么你生成的name属性与你的模型属性不匹配因此,POST方法中的SelectedCompanyID将为0int的默认值)。

ToList()附加到填充companies的语句正在将SelectList转换为List ,表单将不会将其识别为SelectList 。 此外,通过使用动态var关键字,您正在掩盖此问题。 试试这个:

 SelectList companies = new SelectList(await DbContext.Company.ToListAsync(), "CompanyID", "Name"); 

通常,尽量避免使用var除非该类型是真正动态的(直到运行时才知道)。

您将模型数据放在表单之外,因此不会提交!

  

@foreach (var item in Model.Invoices) { }
@Html.DisplayNameFor(model => model.Invoices.FirstOrDefault().InvoiceID) @Html.DisplayNameFor(model => model.Invoices.FirstOrDefault().CompanyID) @Html.DisplayNameFor(model => model.Invoices.FirstOrDefault().Description) @Html.DisplayNameFor(model => model.Invoices.FirstOrDefault().InvoiceDate) @Html.DisplayNameFor(model => model.Invoices.FirstOrDefault().DueDate) @Html.DisplayNameFor(model => model.Invoices.FirstOrDefault().Paid)
@Html.DisplayFor(modelItem => item.InvoiceID) @Html.DisplayFor(modelItem => item.CompanyID) @Html.DisplayFor(modelItem => item.Description) @Html.DisplayFor(modelItem => item.InvoiceDate) @Html.DisplayFor(modelItem => item.DueDate) @Html.DisplayFor(modelItem => item.Paid) @Html.ActionLink("Edit", "Edit", new { id = item.InvoiceID }) | @Html.ActionLink("Details", "Index", "InvoiceItem", new { id = item.InvoiceID }) | @Html.ActionLink("Delete", "Delete", new { id = item.InvoiceID })

使用for循环创建公司将使得映射回来并保持公司价值成为可能

 for(c = 0 ; c < Model.Companies.Count(); c++) { someText /> someText /> } 

这确保列表被映射回来,因为默认模型绑定器期望列表为ListProperty [index]格式