未在ViewModel中填充下拉值

时间:2017-07-27 13:44:28

标签: c# asp.net-mvc viewmodel

我正在研究Hanselman关于MVC的教程,并尝试在“创建”和“编辑”视图中使用视图模型,以便填写下拉菜单。在此,我们将创建一个表Dinner,其中包含TitleCountry列以及相关类,然后是包含dinner对象和{{{ 1}}用于下拉菜单: -

SelectList

这用于在控制器中创建Edit和Create方法。 Edit方法如下所示: -

public class DinnerFormViewModel {
    public Dinner     Dinner    { get; private set; }
    public SelectList Countries { get; private set; }

    public DinnerFormViewModel (Dinner dinner) {
        Dinner    = dinner;
        Countries = new SelectList(...code to create list of countries..., dinner.Country);
    }
}

并且视图中生成的代码如下所示: -

public ActionResult Edit(int id, FormCollection formValues) {
    Dinner dinner = dinnerRepository.GetDinner(id);

    try  {
        UpdateModel(dinner);
        dinnerRepository.Save();
        return RedirectToAction("Details", new { id = dinner.DinnerId });
    }
    catch { ...etc... }
}

到目前为止,这么好。但是当谈到Create方法时,它开始变得有点奇怪。虽然视图中的代码基本相同,但当我调用<div class="editor-field"> <%: Html.EditorFor(model => model.Dinner.Title) %> <%: Html.ValidationMessageFor(model => model.Dinner.Title) %> </div> <div class="editor-field"> <%: Html.DropDownList("Country", Model.Countries) %> <%: Html.ValidationMessage("Country", "*") %> </div> 方法来填充UpdateModel对象时,填充的唯一字段是dinner,来自拉 - 下菜单;当我使用Country进行尝试时,DinnerFormViewModel中的Country保留Dinner,但所有其他字段都已填写。因此,Create方法如下所示: -

null

虽然这有效,但对我来说并不像我应该编写此代码的方式。是不对,或者不是,我该怎么办? (教程中给出的例子没有编译,这是一千个怜悯。)

1 个答案:

答案 0 :(得分:2)

Html.EditorFor(model => model.Dinner.Title)

这会自动映射到您的视图模型,因为生成的HTML name将知道如何映射到Dinner.Title

Html.DropDownList("Country", Model.Countries)

这将为HTML元素指定名称“Country”。这意味着它在发布到您的视图模型时需要model.Country,这在ViewModel上不存在,但在Dinner中确实存在。因此UpdateModel(dinnerFormViewModel);不起作用,但UpdateModel(dinner);确实有效。

所有这些都基于为输入元素生成的name,只要它决定如何分配到视图模型中。我经常在浏览器中检查生成的HTML,以便在POST上映射值时出现问题时检查生成的内容。

您可以使用DropDownListFor,因此您可以指定model.Dinner.Country,以便生成完全符合嵌套关系资格的name

所以现在你明白为什么它不按照你想要的方式工作。从这里开始,你如何更实际地解决它有许多我见过常用的变体,但大多数都涉及到视图模型到实体的某种映射,并且通常在另一层,如业务层,数据访问层,或利用AutoMapper等工具。

您可以将Country属性添加到ViewModel的根目录。

或者我希望在Dinner中没有嵌套属性的情况下使视图模型更平坦,并在发布后将视图模型映射到您的实体。看起来Dinner是您的实体。我从未在我的视图模型中包含我的实体,并且将实体保留在控制器和视图之外是一种非常常见的做法。相反,在GET期间的某个时刻有一个Entity-&gt; ViewModel赋值,然后在post上有一个ViewModel-&gt; Entity映射。当你最终转向分层方法时,这将更有意义。

通过映射我的意思是基本的分配。例如,在检索实体时,您可以将其映射到视图模型,如下所示:

return repo.Get(someId).Select(e => 
   new DinnerFormViewModel {
       HostName = e.HostName,
       // here is an example of flattening out a related entity relationship
       CountryId = e.Location.CountryId, 
       Cost = e.Cost       
   });

当然我编造了一些属性,因为我不知道你的实体是什么样的。

这允许您重构数据库关系,并且只需要更改映射。