0

我正在运行 Visual Studio 2012 调试器,并且发现我的 productViewModelList 参数不包含我希望我的视图传递给我的 [HTTPPOST] 编辑操作的所有值。我不明白为什么。请参考下面代码示例中的注释,了解我插入断点并检查 productViewModelList 值的位置。

为 productViewModelList 提供了以下值:

BrandId = 0,BrandName = "6",BrandSelectListItem = null,ID = 5,Name = "Crutch",价格 = 10.0

  • BrandID 不正确,在我的 DropDownList 的视图中,我指定了“Catatonics Inc.”。它的 ID 为 6,我在我的数据库中进行了验证。
  • BrandName 显示“6”,应在 BrandID 中,BrandName 应为“Catatonics Inc.”。
  • BrandSelectList 项目是 SelectListItem 类型的对象,它包含在我的视图中进入 DropDownList 项目的值。DropDownList 正确显示了值,但 BrandSelectList 是null我的 [httpPost] 编辑操作执行时。我需要访问 DropDownList 的 Selected 项。
  • 所有其他值、ID、名称和价格都是正确的。

这是我的代码中的一些类。

医疗产品控制器

public class MedicalProductController : Controller
{
    private MvcMedicalStoreDb _db = new MvcMedicalStoreDb();

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit(IEnumerable<MedicalProductViewModel> productViewModelList)
    {
        // I have a breakpoint inserted here, and check productViewModelList with debugger.  

        var modelList = GetMedicalProductList(productViewModelList);
        if (ModelState.IsValid)
        {
            foreach (var model in modelList)
                _db.Entry(model).State = EntityState.Modified;

            _db.SaveChanges();
            return RedirectToAction("Index");
        }

        return View(productViewModelList);
    }
}

医疗产品映射器

public class MedicalProductMapper
{

    public IEnumerable<MedicalProductViewModel> MapMedicalProductViewModel(IEnumerable<MedicalProduct> productList, IEnumerable<Brand> brandList)
    {
        var brandSelectListItem = brandList.Select(b => new SelectListItem()
                                                {
                                                    Text = b.Name,
                                                    Value = b.ID.ToString()
                                                });

        var viewModelList = productList.Select(p => new MedicalProductViewModel() 
                                {
                                    BrandID = p.BrandID,
                                    BrandName = brandList.SingleOrDefault(b => b.ID == p.BrandID).Name,
                                    BrandSelectListItem = brandSelectListItem,
                                    ID = p.ID,
                                    Price = p.Price,
                                    Name = p.Name
                                });

        return viewModelList;
    }

    public IEnumerable<MedicalProduct> MapMedicalProductList(IEnumerable<MedicalProductViewModel> viewModelList)
    {
        var modelList = viewModelList.ToArray().Select( viewModel => new MedicalProduct()
        {
            Name = viewModel.Name,
            Price = viewModel.Price,
            BrandID = Convert.ToInt32(viewModel.BrandSelectListItem.Select(b => b.Value.ToString()))
        });

        return modelList;
    }
}

编辑.cshtml

@model IEnumerable<MvcMedicalStore.Models.MedicalProductViewModel>

@{
    ViewBag.Title = "Edit";
}

<h2>Edit</h2>

@using (Html.BeginForm()) {
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(true)

    <fieldset>
        <legend>MedicalProduct</legend>
        @Html.EditorFor(m => m)        
        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

EditorTemplates/MedicalProductViewModel.cshtml

(这是在 Edit.cshtml 目录的子目录中。)

@model MvcMedicalStore.Models.MedicalProductViewModel

@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.BrandName)
</div>
<div class="editor-field">
    @Html.DropDownListFor(item => Model.BrandName, Model.BrandSelectListItem)
    @Html.ValidationMessageFor(item => Model.BrandName)
</div>

编辑:

品牌

public class Brand
{
    [Key]
    public int ID { get; set; }

    [Required]
    [StringLength(30)]
    public string Name { get; set; }
}

医疗产品

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 MedicalProductViewModel
{
    [Key]
    public int ID { get; set; }

    [Required]
    [StringLength(50)]
    public string Name { get; set; }

    [Required]
    [DataType(DataType.Currency)]
    public double Price { get; set; }

    public int BrandID { get; set; }

    [DisplayFormat(NullDisplayText="[Generic]")]
    public string BrandName { get; set; }

    public IEnumerable<SelectListItem> BrandSelectListItem { get; set; }
}
4

1 回答 1

0

您没有用于 的表单元素BrandID,因此当模型绑定器将表单 POST 转换为模型时,它将使用 的默认值int,即 0。您确实有用于 的表单元素BrandName

@Html.DropDownListFor(item => Model.BrandName, Model.BrandSelectListItem)

这大概是(取决于 的定义BrandSelectListItem,并基于您描述的观察到的行为)将创建一个select元素,其中option元素使用可用BrandName值作为文本,可用BrandID值作为值。当一个select元素包含在 HTTP POST 中时,选择的值就是发布的内容。因此,您获得了 selected ,但通过将其绑定到模型上的该属性来BrandID将其分配给值。BrandName

听起来你真正想要的是这样的:

@Html.DropDownListFor(item => Model.BrandID, Model.BrandSelectListItem)

这会给你:

BrandId = 6, BrandName = "", BrandSelectListItem = null, ID = 5, Name = "Crutch", Price = 10.0

你仍然没有BrandName值,但在这种情况下你真的需要一个吗?是重复数据。该模型可以动态地确定BrandName从已知的BrandID. 所以BrandName不需要是模型上的读/写属性,它可以只是一个只读属性,它BrandName基于模型的BrandID. 它可能很简单:

public string BrandName
{
    get
    {
        var brandName = GetBrandName(BrandID);
        return brandName;
    }
}

在这种情况下,您将实现GetBrandName从数据存储中获取值。或者,如果它足够清晰和简洁,那么就可以在线完成整个事情,这取决于您。您还可以将值缓存在类级别的私有变量中,以便只需要获取一次。(只要确保清除该变量或在任何BrandID更改时重新获取它。)

可以将这两个属性保持原样,但随后您将负责确保它们在对象的生命周期内保持同步,其中包括它在 UI 中花费的时间。每当您在两个地方记录相同的信息时,您都有责任保持同步。这从来都不好玩。在这种情况下,您需要视图中的两个元素(第二个可能是隐藏的表单字段,或者可能是样式为隐藏的下拉列表),并且您必须编写一些 JavaScript 来随时更新一个另一个变化。

于 2013-10-04T19:29:42.033 回答