【问题标题】:ASP.NET MVC 3 - EF 4.2 code-first - master-detail editingASP.NET MVC 3 - EF 4.2 代码优先 - 主从编辑
【发布时间】:2012-02-11 05:34:45
【问题描述】:

我对 ASP.NET MVC 3 中的一个问题感到困惑 - 从单个 MVC 视图处理主从关系的编辑和更新。

我正在使用 Entity Framework 4.2 代码优先来构建一个小应用程序。它使用Person 类(具有NameFirstName 等)和Address 类(具有StreetZipcodeCity 等)。

这两个类彼此之间具有 m:n 关系,在 EF 代码优先中建模:

public class Person
{
    private List<Address> _addresses;

    // bunch of scalar properties like ID, name, firstname

    public virtual List<Address> Addresses
    {
        get { return _addresses; }
        set { _addresses = value; }
    }
}

public class Address
{
    private List<Person> _people;

    // bunch of scalar properties like AddressID, street, zip, city

    public virtual List<Person> People
    {
        get { return _people; }
        set { _people = value; }
    }
}

我用一些数据手动填充了数据库,并且使用 EF 4.2 检索数据工作得很好。

我有一个 ASP.NET MVC PersonController,我在其中加载了一个 Person,包括其所有当前地址,并使用 Razor 视图显示它。我想允许用户更改或更新现有地址,以及删除或插入地址。控制器从 WCF 服务获取该人的数据,如下所示:

public ActionResult Edit(int id)
{
    Person person = _service.GetPerson(id);
    return View(person);
}

并且检索时该人的地址已正确填写。

此视图工作正常 - 它按预期显示来自 Person 实例的所有数据。

@model DomainModel.Person

<h2>Edit</h2>

@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>Person</legend>

        @Html.HiddenFor(model => model.PersonId)

        <div class="editor-label">
            @Html.LabelFor(model => model.Name)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Name)
            @Html.ValidationMessageFor(model => model.Name)
        </div>

        .... and a few more of those scalar properties being edited....  

        <hr/>
        <h4>Addresses</h4>

        @foreach (var item in Model.Addresses)
        {
            <tr>
                <td>
                    @Html.EditorFor(modelItem => item.Street)
                </td>
                <td>
                    @Html.EditorFor(modelItem => item.ZipCode)
                </td>
                <td>
                    @Html.EditorFor(modelItem => item.City)
                </td>
            </tr>
        }
        <hr/>
        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
}

但是,当我在保存正在编辑的人时尝试处理 POST 时,我似乎无法访问视图中显示(并且可能已编辑)的地址:

    [HttpPost]
    public ActionResult Edit(Person person)
    {
        if (ModelState.IsValid)
        {
            _service.UpdatePerson(person);
            return RedirectToAction("Index");
        }
        return View(person);
    } 

在这种情况下,person.Addresses 属性始终为 null。嗯....我错过了什么?如何在 ASP.NET MVC 视图上编辑人员到地址的关系,并从我的视图中取回 Person AND 与其关联的 Addresses,以便我可以将它们传递给 EF将它们保存回数据库表?

【问题讨论】:

    标签: asp.net-mvc-3 sql-server-2008 entity-framework-4 ef-code-first master-detail


    【解决方案1】:

    我怀疑地址的输入字段名称错误。

    我建议您使用编辑器模板。因此,将 Razor 视图中的 @foreach 循环替换为对 Addresses 属性的 EditorFor 助手的一次调用:

    <h4>Addresses</h4>
    
    @Html.EditorFor(x => x.Addresses)
    
    <hr/>
    

    现在为地址定义一个编辑器模板,它将为集合的每个元素自动呈现 (~/Views/Shared/EditorTemplates/Address.cshtml):

    @model Address
    <tr>
        <td>
            @Html.EditorFor(x => x.Street)
        </td>
        <td>
            @Html.EditorFor(x => x.ZipCode)
        </td>
        <td>
            @Html.EditorFor(x => x.City)
        </td>
    </tr>
    

    现在,当您提交时,您的 Person 模型上的 Addresses 属性将被正确绑定。

    备注:编辑器模板也可以放在~/Views/XXX/EditorTemplates/Address.cshtml 中,其中XXX 是当前控制器。在这种情况下,它只能在当前控制器的视图中重用,而不是使其全局可见(通过将其放入 Shared 中)。

    有关默认模型绑定器的线格式如何更深入的概述,您可以查看following article

    【讨论】:

    • +1 很棒的东西 - 谢谢!我对 MVC 还有些陌生,还没有完全“接受”它所有的奇妙功能!
    【解决方案2】:

    相信你将foreach块改为for块,如下所示,你会得到想要的效果:

        @for (var i = 0; i < Model.Addresses.Count(); i++)
        {
            <tr>
                <td>
                    @Html.EditorFor(model => model.Addresses[i].Street)
                </td>
                <td>
                    @Html.EditorFor(model => model.Addresses[i].ZipCode)
                </td>
                <td>
                    @Html.EditorFor(model => model.Addresses[i].City)
                </td>
            </tr>
        }
    

    这当然要求地址集合可以通过索引访问。

    原因是在foreach 块中生成的 html 将类似于:

    <input type="text" name="Street" value="Test Street 1" />
    

    for 块将改为生成如下内容:

    <input type="text" name="Addresses[0].Street" value="Test Street 1" />
    

    然后模型绑定器使用表单字段名称将其与模型类的属性相匹配。

    这两个示例都经过简化以理解重点,并非 100% 正确。

    【讨论】:

    • 嗯...有趣....是的,这似乎有效。知道为什么这行得通(使用索引的for 循环)而@foreach 不行吗??
    • 这与 MVC 如何呈现 html 和绑定模型有关。使用 foreach 不会为可以映射到模型的输入字段呈现名称属性。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-07
    • 1970-01-01
    相关资源
    最近更新 更多