单击“保存”以提交表单时,我的HTTPPost编辑操作会收到IEnumerable<MedicalProduct> productList
的空值。我不确定我的编辑Action使用什么参数来防止空值。我会尝试用一些断点确定原因但在参数被赋值为null之前找不到该位置。
旁注:
我正在调整我的代码以使用这个新的Model / ViewModel层次结构。我的Controller尚未使用这些新模型进行完全测试,但我开始测试编辑操作,并在尝试在编辑后期操作中使用参数IEnumerable<MedicalProduct> productList
时收到空引用异常。
另一方注意:
我在ViewModel MedicalProductViewModelLineItem
中使用了一个子ViewModel类MedicalProductViewModel
(尚未找到更好的名称)因为我需要一种从数据库中检索所有品牌名称的方法一个数据库调用,然后逐个分配给MedicalProductViewModelLineItem
。
编辑:CODE UPDATE 10/22/13 5:14 pm CST 。现在修复了HttpPost FormCollection.Keys
操作方法中Edit
参数中生成的值。现在,像“Products [0] .Name”或“Products [0] .ID”这样的值是在FormCollection.Keys
参数而不是“p.Name”或“Name”中生成的。 但是 ,productList
参数仍为null
。
public class MedicalProductViewModel
{
public List<MedicalProductViewModelLineItem> Products { get; private set; }
//public SelectListItem BrandSelectListItem { get; private set; }
public void BuildViewModel(IEnumerable<MedicalProductViewModelLineItem> productsList, IEnumerable<Brand> brandList)
{
BuildProducts(productsList, brandList);
}
public void BuildViewModel(IEnumerable<MedicalProduct> productsList, IEnumerable<Brand> brandList)
{
BuildProducts(productsList, brandList);
}
private IEnumerable<SelectListItem> BuildSelectListItems(IEnumerable<Brand> brandList)
{
return brandList.Select(b => new SelectListItem()
{
Text = b.Name,
Value = b.ID.ToString()
});
}
private void BuildProducts(IEnumerable<MedicalProductViewModelLineItem> productList, IEnumerable<Brand> brandList)
{
var medicalProducts = productList.Select(p => new MedicalProduct()
{
BrandID = p.BrandID,
ID = p.ID,
Name = p.Name,
Price = p.Price
});
BuildProducts(medicalProducts, brandList);
}
private void BuildProducts(IEnumerable<MedicalProduct> productsList, IEnumerable<Brand> brandList)
{
Products = productsList.Select(p => new MedicalProductViewModelLineItem()
{
BrandID = p.BrandID,
BrandName = brandList.Single(b => b.ID == p.BrandID).Name,
BrandSelectListItem = BuildSelectListItems(brandList),
ID = p.ID,
Name = p.Name,
Price = p.Price
}).ToList();
}
}
// Sub-ViewModel of MedicalProductViewModel
// It gets displayed as one row on a view.
public class MedicalProductViewModelLineItem
{
[Key]
public int ID { get; set; }
[Required]
[StringLength(50)]
public string Name { get; set; }
[Required]
[DataType(DataType.Currency)]
public double Price { get; set; }
// is a foreign key
public int BrandID { get; set; }
public string BrandName { get; set; }
}
// DOMAIN MODEL
public class MedicalProduct
{
[Key]
public int ID { get; set; }
[Required]
[StringLength(50)]
public string Name { get; set; }
[Required]
[DataType(DataType.Currency)]
public double Price { get; set; }
// is a foreign key
public int BrandID { get; set; }
}
public class MedicalProductController : Controller
{
private MvcMedicalStoreDb _db = new MvcMedicalStoreDb()
//
// GET: /MedicalSupply/Edit/5
public ActionResult Edit(int id = 0)
{
MedicalProduct product = _db.Products.Find(id);
if (product == null)
{
return HttpNotFound();
}
var productList = new List<MedicalProduct> { product };
var viewModel = GetMedicalProductViewModel(productList);
return View(viewModel);
}
// ==========================================
// NULL REFERENCE EXCEPTION OCCURS IN THIS ACTION
// ==========================================
// POST: /MedicalSupply/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(IEnumerable<MedicalProductViewModelLineItem> productList, FormCollection values)
{
if (ModelState.IsValid)
{
foreach (var product in productList)
_db.Entry(product).State = EntityState.Modified;
_db.SaveChanges();
return RedirectToAction("Index");
}
var productViewModelList = GetMedicalProductViewModel(productList);
return View(productViewModelList);
}
protected override void Dispose(bool disposing)
{
_db.Dispose();
base.Dispose(disposing);
}
}
@model MvcMedicalStore.Models.MedicalProductViewModel
@{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
@using (Html.BeginForm()) {
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)
<fieldset>
<legend>MedicalProduct</legend>
@for (int i = 0; i < Model.Products.Count(); i++)
{
@Html.EditorFor(m => m.Products[i])
}
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
@model MvcMedicalStore.Models.MedicalProductViewModelLineItem
@Html.HiddenFor(item => Model.ID)
<div class="editor-label">
@Html.LabelFor(item => Model.Name)
</div>
<div class="editor-field">
@Html.EditorFor(item => Model.Name)
@Html.ValidationMessageFor(item => Model.Name)
</div>
<div class="editor-label">
@Html.LabelFor(item => Model.Price)
</div>
<div class="editor-field">
@Html.EditorFor(item => Model.Price)
@Html.ValidationMessageFor(item => Model.Price)
</div>
<div class="editor-label">
@Html.LabelFor(item => Model.BrandID)
</div>
<div class="editor-field">
@Html.DropDownListFor(item => Model.BrandID, Model.BrandSelectListItem)
@Html.ValidationMessageFor(item => Model.BrandID)
</div>
MedicalProductViewModel.cshtml中使用的foreach
方法和for
方法的两张图片,以及FormsCollection
参数values
的结果键值
答案 0 :(得分:2)
在您的控制器操作中使用BindAttribute
Prefix
,如下所示:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Prefix = "Products")] IEnumerable<MedicalProductViewModelLineItem> productList)
{
if (ModelState.IsValid)
{
foreach (var product in productList)
_db.Entry(product).State = EntityState.Modified;
_db.SaveChanges();
return RedirectToAction("Index");
}
var productViewModelList = GetMedicalProductViewModel(productList);
return View(productViewModelList);
}
答案 1 :(得分:0)
将您的视图从foreach循环更改为for循环
@foreach (MvcMedicalStore.Models.MedicalProductViewModelLineItem p in Model.Products)
{
@Html.HiddenFor(item => p.ID)
//rest of the code.
}
to
@for ( i = 0; i < Model.count(); i++)
{
@Html.LabelFor(m => m[i].Name)
@Html.HiddenFor(m => m[i].Name)
@Html.LabelFor(m => m[i].Price)
@Html.EditorFor(m => m[i].Price)
//rest of the code.
}
[HttpPost]
public MedicalProductViewModel GetMedicalProductViewModel(ICollection<MedicalProduct> productList)
{
var brandList = _db.Brands.ToArray();
var mapper = new MedicalProductMapper();
return mapper.MapMedicalProductViewModel(productList, brandList);
}
使其更明确,指定
FormMethod.Post
@using (Html.BeginForm()) { }
到
@using (Html.BeginForm("Action", "Controller", FormMethod.Post, new { id = "forId" }))
{}