0

单击保存以提交我的表单时,我的 HTTPPost 编辑操作收到一个空值IEnumerable<MedicalProduct> productList。我不确定要为我的编辑操作使用什么参数来防止空值。我会尝试用一些断点来确定原因,但在将参数分配为 null 之前找不到该点。

边注:

我正在调整我的代码以使用这个新的模型/视图模型层次结构。我的控制器尚未使用这些新模型进行完全测试,但我开始测试编辑操作,并在尝试IEnumerable<MedicalProduct> productList在我的编辑发布操作中使用参数时收到空引用异常。

另一个旁注:

我在 ViewModel 中使用了一个子 ViewModel 类MedicalProductViewModelLineItem(还没有找到更好的名称),MedicalProductViewModel因为我需要一种方法来通过一次数据库调用从数据库中检索所有品牌名称,然后将它们一一分配给MedicalProductViewModelLineItem.

编辑:代码更新 2013 年 10 月 22 日下午 5:14 CSTFormCollection.KeysHttpPostEdit操作方法生成的值现在,像“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();
    }
}

MedicalProductViewModelLineItem

// 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);
    }
}

意见


编辑.cshtml

@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")
}

EditorTemplates\MedicalProductViewModelLineItem.cshtml

@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的结果键值FormsCollectionvalues

使用 for 方法 使用 foreach 方法

4

2 回答 2

2

在您的控制器操作中使用BindAttributewith ,如下所示: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);
}
于 2013-10-23T14:39:04.427 回答
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);            
    }

使其更明确,指定

表单方法.Post

@using (Html.BeginForm()) { }

@using (Html.BeginForm("Action", "Controller", FormMethod.Post, new { id = "forId" }))
    {}
于 2013-10-13T18:57:42.943 回答