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



我在ASP.NET MVC 3中遇到了一个问题——从单个MVC视图处理主-细节关系的编辑和更新。

我首先使用实体框架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关系,并从视图中获取Personand及其关联的Addresses,以便将它们传递给EF以将它们保存回数据库表??

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

我建议您使用编辑器模板。因此,将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中)。

有关默认模型绑定器的有线格式的更深入的概述,您可以查看下面的文章。

我相信通过将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%正确。

最新更新