我对ASP.NET MVC 3中的一个问题感到困惑 - 处理从单个MVC视图编辑和更新主 - 详细信息关系。
我正在使用Entity Framework 4.2代码优先构建一个小应用程序。它使用Person
类(包含Name
,FirstName
等)和Address
类(包含Street
,Zipcode
, City
等。)。
这两个类彼此之间具有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以将它们保存回数据库表?
答案 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%正确。