ASP.NET MVC 3 - EF 4.2 代码优先 - 主从编辑
我被 ASP.NET MVC 3 中的一个问题所困扰 - 从单个 MVC 视图处理主从关系的编辑和更新。
我正在使用 Entity Framework 4.2 代码优先来构建一个小型应用程序。它使用 Person
类(其中包含 Name
、FirstName
等)和 Address
类(包含街道
、邮政编码
、城市
等)。
这两个类彼此之间具有 am: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
在这种情况下,属性始终为空。嗯...我错过了什么?如何在 ASP.NET MVC 视图上编辑 Person-to-Addresses 关系,并从以下位置获取 Person
AND 其关联的 Addresses
我的观点是,所以我可以将它们传递给 EF 以将它们保存回数据库表?
I'm stumped with a problem in ASP.NET MVC 3 - handling editing and updating of a master-detail relationship from a single MVC view.
I'm using Entity Framework 4.2 code-first to build a small app. It uses a Person
class (which has Name
, FirstName
and so on), and an Address
class (with Street
, Zipcode
, City
etc.).
These two classes have a m:n relationship to one another, modelled in EF code-first with:
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; }
}
}
I filled the database manually with some data and retrieval of the data using EF 4.2 works just fine.
I have an ASP.NET MVC PersonController
, in which I am loading a Person
including all its current addresses, and show it using a Razor view. I'd like to allow the user to change or update existing addresses, as well as delete or insert addresses. The controller gets the data for that person from a WCF service like this:
public ActionResult Edit(int id)
{
Person person = _service.GetPerson(id);
return View(person);
}
and the person's addresses are filled properly when retrieving.
The view for this works fine - it shows all the data from the Person
instance as expected.
@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>
}
However, when I'm trying to handle the POST upon saving the person being edited, I cannot seem to get access to the addresses that were displayed (and possibly edited) in the view:
[HttpPost]
public ActionResult Edit(Person person)
{
if (ModelState.IsValid)
{
_service.UpdatePerson(person);
return RedirectToAction("Index");
}
return View(person);
}
The person.Addresses
property is always null in this case. Hmmm.... what am I missing?? How can I edit a Person-to-Addresses relationship on an ASP.NET MVC view, and get back the Person
AND its associated Addresses
from my view, so I can pass them to EF to save them back to the database tables??
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我怀疑地址的输入字段名称错误。
我建议您使用编辑器模板。因此,将 Razor 视图中的
@foreach
循环替换为对 Addresses 属性的EditorFor
帮助器的一次调用:现在为地址定义一个编辑器模板,该模板将自动为集合的每个元素呈现 (
~/Views/Shared/EditorTemplates/Address.cshtml
):现在,当您提交时,Person 模型上的
Addresses
属性将正确显示边界。备注:编辑器模板也可以放置在
~/Views/XXX/EditorTemplates/Address.cshtml
中,其中 XXX 是当前控制器。在这种情况下,它只能在当前控制器的视图中重用,而不是使其全局可见(通过将其放入 Shared 中)。有关默认模型绑定器的有线格式的更深入概述,您可以查看 以下文章。
I suspect that the input fields for the address have wrong names.
I would suggest you using editor templates. So replace your
@foreach
loop in the Razor view with a single call of theEditorFor
helper for the Addresses property:and now define an editor template for the address which will automatically be rendered for each element of the collection (
~/Views/Shared/EditorTemplates/Address.cshtml
):Now when you submit, the
Addresses
property on your Person model will be correctly bound.Remark: the editor template could also be placed inside
~/Views/XXX/EditorTemplates/Address.cshtml
where XXX is the current controller. In this case it can be reused only within the views of the current controller instead of making it globally visible (by putting it in Shared).For more in-depth overview of how the wire format of the default model binder you may take a look at the following article.
我相信通过将 foreach 块更改为 for 块,您将获得所需的效果,如下所示:
这当然要求可以通过索引访问 Addresses 集合。
这样做的原因是,在
foreach
块中,生成的 html 将类似于:for
块将生成类似以下内容的内容:然后模型绑定器使用表单字段名称将其与模型类的属性进行匹配。
这两个示例都经过简化以表达要点,但并非 100% 正确。
I believe you'll get the desired effect by changing the foreach block to a for block as follows:
This of course require that the Addresses collection is accessible by index.
The reason for this is that in the
foreach
block the resulting html will be something like:The
for
block will instead generate something like:The model binder then uses the form field name to match it against the properties of the model class.
Both examples are simplified to get the point across and aren't 100% correct.