未在ViewModel中填写下拉值 [英] Pulldown values not filled in in ViewModel

查看:66
本文介绍了未在ViewModel中填写下拉值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究Hanselman的MVC教程,并尝试在创建"和编辑"视图中使用视图模型以填充下拉菜单.在此,我们指导创建一个表 Dinner ,其列包括 Title Country 以及相关类,然后创建一个包含 dinner 对象和一个下拉菜单的 SelectList ,因此:-

I am working through Hanselman's tutorial on MVC, and attempting to use a view model in the Create and Edit views so as to fill in a pulldown menu. In this we are directed to create a table Dinner, with columns including Title and Country and the related classes, and then a ViewModel containing a dinner object and a SelectList for a pull-down menu thus:-

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

我用来在控​​制器中创建Edit和Create方法.Edit方法如下所示:-

This I use to create Edit and Create methods in the controller. The Edit method looks like this:-

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... }
}

和在视图中生成的代码如下:-

and the code generated in the view looks like this:-

<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>

到目前为止,太好了.但是当涉及到Create方法时,它开始变得有些奇怪.尽管视图中的代码本质上是相同的,但是当我调用 UpdateModel 方法来填充 dinner 对象时,唯一要填充的字段是 Country,从下拉菜单中;当我尝试使用 DinnerFormViewModel 时, Dinner 中的 Country 保留为 null ,但其他所有字段被填充.因此Create方法看起来像这样:-

So far, so good. But when it comes to the Create method it starts to get a bit strange. While the code in the view is essentially identical, when I invoke the UpdateModel method to fill in the dinner object, the only field that is filled in is the Country, from the pull-down menu; when I try it with the DinnerFormViewModel, the Country in the Dinner is left null, but all the other fields are filled in. So the Create method looks like this:-

public ActionResult Create(FormCollection formValues) {
    Dinner              dinner              = new Dinner();
    DinnerFormViewModel dinnerFormViewModel = new DinnerFormViewModel(new Dinner());

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

虽然这可行,但在我看来却不是我编写此代码的方式.是对的还是不正确的,我应该怎么做?(很遗憾,本教程中的示例未编译.)

While this works, it doesn't to me look like it is the way I should be writing this code. Is it right, or if it isn't, what should I be doing? (It is a thousand pities that the example given in the tutorial doesn't compile.)

推荐答案

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

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

This maps automatically to your view model because the HTML name generated will know how to map to Dinner.Title

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

这将使HTML元素的名称为国家/地区".这意味着在发布到视图模型时,它需要一个 model.Country ,该模型在ViewModel中不存在,但在Dinner中存在.因此 UpdateModel(dinnerFormViewModel); 不起作用,但是 UpdateModel(dinner); 起作用.

This will give the HTML element the name "Country". This means it expects a model.Country when posting to your view model, which doesn't exist on your ViewModel, but does exist in Dinner. Hence UpdateModel(dinnerFormViewModel); does not work but UpdateModel(dinner); does work.

这全都是基于为输入元素生成的 name 的,它决定了如何分配视图模型.我经常在浏览器中检查生成的HTML,以检查在POST上映射值时遇到问题时正在生成的内容.

It's all based on the name that is generated for the input elements as far as how it decides assignment into the view model. I often inspect the generated HTML in the browser to sanity check what is being generated when there are problems mapping values on POST.

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

You could use DropDownListFor so you could specify the model.Dinner.Country so that it would generate a name that is fully qualified for the nested relationship.

因此,您现在了解了为什么它无法按您希望的方式工作.从这里开始,您如何更实际地解决它有很多我常用的变体,但是大多数变体涉及到视图模型到实体的某种映射,并且通常涉及另一层,例如业务层,数据访问层.,或利用诸如AutoMapper之类的工具.

So now you understand why it didn't work the way you wanted it to. From here, how you solve it more practically has many variations that I've seen commonly used, but most will involve some sort of mapping of the view model to the entity, and often in another layer such as a business layer, data access layer, or leveraging a tool such as AutoMapper.

您可以将Country属性添加到ViewModel的根.

You could add a Country property to the root of your ViewModel.

或者我更希望使视图模型更加平坦,以使属性不嵌套在 Dinner 中,并在其发布后将视图模型映射到您的实体.看来 Dinner 是您的实体.我从不在视图模型中包含实体,而将实体保持在控制器和视图之外是一种很常见的做法.取而代之的是,在GET期间的某个时候有一个Entity-> ViewModel分配,然后是一个Post上的ViewModel-> Entity映射.最终转移到分层方法时,这将更有意义.

Or I would prefer making your view model more flat where the properties are not nested in Dinner, and after it posts, map your view model to your entity. It looks like Dinner is your entity. I never include my entity in my view model, and keeping entities out of controllers and views is a pretty common practice. Instead there is a Entity->ViewModel assignment at some point during GET, and then a ViewModel->Entity mapping on post. This will make more sense as you eventual move to a layered approach.

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

By mapping I mean basic assignment. For example, when retrieving your entity, you could map it to your view model like so:

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

我当然组成了一些属性,因为我不知道您的实体是什么样.

Of course I made up some properties because I don't know what your entity looks like.

这使您可以重构数据库关系,而只需更改映射.

This allows you to refactor your DB relationships, and you only need to change your mapping.

这篇关于未在ViewModel中填写下拉值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆