ASP.NET MVC 3 - EF 4.2代码优先 - 主 - 细节编辑

时间:2012-01-16 08:23:05

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

我对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-to-Addresses关系,并从我的视图中返回Person AND 与其关联的Addresses,这样我就可以将它们传递给EF以将它们保存回数据库表?

2 个答案:

答案 0 :(得分:2)

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

我建议您使用编辑器模板。因此,只需调用Addresses属性的@foreach帮助器,就可以替换Razor视图中的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是当前控制器。在这种情况下,它只能在当前控制器的视图中重用,而不是使其全局可见(通过将其置于共享中)。

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

答案 1 :(得分: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>
    }

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

原因是在foreach块中生成的html会是这样的:

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

for块将生成如下内容:

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

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

这两个示例都经过简化以获得重点并且不是100%正确。