在Asp.Net MVC 3应用程序中收集复杂的子对象?

时间:2011-02-20 23:19:28

标签: asp.net entity-framework collections asp.net-mvc-3 entity

我希望能够在同一视图中更新模型及其所有子对象集合。我已经参考了这些示例:http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspxhttp://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/

例如,我有一个对象顾问,它有一个“WorkExperiences”的集合。所有这些都在实体框架模型中。在视图中,Consultant对象的简单属性没有问题,但是我无法获得要显示的文本框的集合。我尝试按照上面的链接中的示例,但它不起作用。问题是,在这些示例中,模型只是一个列表(不是具有子列表属性的对象)。而且,该模型再次是EF模型。由于某些原因,这些例子似乎不起作用。

为了简单起见,我尝试按照Phil Haacks的例子做一些事情,然后让View显示文本框:

@for (int i = 0; i < Model.WorkExperiences.Count; i++)
{
    Html.TextBoxFor(m => m.WorkExperiences[i].Name);
}

我尝试在控制器中为ViewModel创建一个新的WorkExperience对象:

    public ActionResult Create(int id)
    {
        Consultant consultant = _repository.GetConsultant(id);
        DetailsViewModel vm = new DetailsViewModel();
        vm.WorkExperiences = consultant.WorkExperiences.ToList();
        vm.WorkExperiences.Add(new WorkExperience());           
        return View(vm);
    }

但View不显示WorkExperience Name属性的任何空文本框。另一方面,我创建一个单独的View只是为了添加一个新的WorkExperience对象,传递一个新的空WorkExperience对象作为模型,这很好用:

@Html.EditorFor(model => model.Name)

这给了我一个空文本框,我可以保存新对象。但是为什么我不能在与Consultant对象相同的视图中执行此操作,根据上面链接中的示例使用集合?

顺便说一句,这是对前一个问题的后续问题,它指出了上述链接,但我从来没有找到最终的解决方案。如果需要更多信息,请查看该问题:Create Views for object properties in model in MVC 3 application?

更新:

根据下面的答案和评论,这里是View和EditorTemplate的更新:

观点:

@model Consultants.ViewModels.DetailsViewModel

@{
    ViewBag.Title = "Index";
}

<h2>Index</h2>

<p>
    @Html.ActionLink("Add work experience", "CreateWorkExperience", new { id = ViewBag.Consultant.Id })
</p>
<table>
    <tr>
        <th></th>
        <th>
            Name
        </th>

    </tr>

@foreach (var item in Model.WorkExperiences) {
    <tr>
        <td>
            @Html.ActionLink("Edit", "Edit", new { id = item.Id }) |
            @Html.ActionLink("Details", "Details", new { id = item.Id }) |
            @Html.ActionLink("Delete", "Delete", new { id = item.Id })
        </td>
        <td>
            @item.Name
        </td>

    </tr>

}

</table>

@for (int i = 0; i < Model. WorkExperiences.Count; i++)
{
    Html.EditorFor(m => m. WorkExperiences[i]);
}

(请注意,所有这些并不是我最终将如何设计它,我现在所追求的是让WorkExperience对象显示为一个空的文本框来填写,并且能够添加和删​​除Phil Haack和Steven Sanderson的例子中的文本框。)

EditorTemplate:

@model Consultants.Models.WorkExperience


@Html.TextBoxFor(m => m.Name);

使用EditorTemplate的这个东西在Phil Haack的示例项目中运行良好,我下载试用,但是在这里,使用EF模型或者任何问题,我根本没有得到任何文本框。视图中的表只是作为测试,因为在表中我确实获得了WorkExperiences的行,无论我添加一个空的WorkExperience对象还是填写其属性无关紧要,每个对象都显示行。但同样,没有文本框......

2 个答案:

答案 0 :(得分:12)

  

例如,我有一个对象顾问,它有一个“WorkExperiences”的集合。所有这些都在实体框架模型中。

这是您应该改进的第一件事:介绍视图模型,不要将您的域模型用于视图。

这就是说让我们转到模板。因此,您可以完全消除在视图中编写循环的需要。

以下是您的观点的样子:

@model Consultants.ViewModels.DetailsViewModel

@{
    ViewBag.Title = "Index";
}

<h2>Index</h2>

<p>
    @Html.ActionLink("Add work experience", "CreateWorkExperience", new { id = ViewBag.Consultant.Id })
</p>
<table>
    <tr>
        <th></th>
        <th>
            Name
        </th>
    </tr>
    @Html.DisplayFor(x => x.WorkExperiences)
</table>

@Html.EditorFor(x.WorkExperiences)

因此,我们可以使用显示模板和编辑器模板。我们现在定义它们。

显示模板(~/Views/Shared/DisplayTemplates/WorkExperience.cshtml):

@model AppName.Models.WorkExperience
<tr>
    <td>
        @Html.ActionLink("Edit", "Edit", new { id = Model.Id }) |
        @Html.ActionLink("Details", "Details", new { id = Model.Id }) |
        @Html.ActionLink("Delete", "Delete", new { id = Model.Id })
    </td>
    <td>
        @Model.Name
    </td>
</tr>

编辑模板(~/Views/Shared/EditorTemplates/WorkExperience.cshtml):

@model AppName.Models.WorkExperience
@Html.TextBoxFor(x => x.SomePropertyOfTheWorkExperienceModelYouWantToEdit)
...

这里重要的是命名约定。模板的名称应该是集合中项目类型的名称。因此,例如,如果在您的视图模型中,您有一个属性

public IEnumerable<Foo> { get; set; }

相应的模板应该被称为Foo.cshtml,并且应该位于~/Views/Shared/DisplayTemplates~/Views/Shared/EditorTemplates,具体取决于其角色。

所以你可以看到我们已经摆脱了讨厌的循环。现在不仅视图看起来干净,而且您获得了输入字段的正确名称,以便您可以在post操作中将值绑定回来。

答案 1 :(得分:0)

最简单的方法是创建一个WorkExperienceList类,继承List<WorkExperience>(或List<string>,如果它们是这样的话),然后为您的{创建自定义模板{1}}。这样,您就可以将视图代码简化为WorkExperienceList,ASP.NET MVC将为您完成剩下的工作。