FOR*_*FOR 10 model-binding asp.net-mvc-3
TL; DR:在我的ASP.NET MVC3应用程序中,我应该如何实现一个允许我在"子"实体列表的详细信息的同时编辑"父"实体的详细信息的视图?
更新:我接受了@ torm的答案,因为他提供了一个链接,可以解释为什么我当前的解决方案可能会有所改善.但是,如果有其他人有任何选择,我们很乐意听到!
我一直在寻找和阅读(到目前为止的一些调查结果,请参见底部的"参考文献"部分).然而,我仍然觉得到目前为止我找到的解决方案有点"臭".我想知道你们中是否有人有更优雅的答案或建议(或者可以解释为什么这可能会"变得如此好").提前致谢!
所以,这是设置:
public class Wishlist
{
public Wishlist() { Wishitems = new List<Wishitem>(); }
public long WishListId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public virtual ICollection<Wishitem> Wishitems { get; set; }
}
public class Wishitem
{
public long WishitemId { get; set; }
public string Name { get; set; }
public int Quantity { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
public class WishlistsController : Controller
{
private SandboxDbContext db = new SandboxDbContext();
/* ... */
public ActionResult Edit(long id)
{
Wishlist wishlist = db.Wishlists.Find(id);
return View(wishlist);
}
[HttpPost]
public ActionResult Edit(Wishlist wishlist)
//OR (see below): Edit(Wishlist wishlist, ICollection<Wishitem> wishitems)
{
if (ModelState.IsValid)
{
db.Entry(wishlist).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(wishlist);
}
/* ... */
}
Run Code Online (Sandbox Code Playgroud)
@model Sandbox.Models.Wishlist
<h2>Edit</h2>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
@using (Html.BeginForm())
{
@Html.ValidationSummary(true)
<fieldset>
<legend>Wishlist</legend>
@Html.HiddenFor(model => model.WishListId)
<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>
</fieldset>
<table>
<tr>
<th>
Quantity
</th>
<th>
Name
</th>
</tr>
@for (var itemIndex = 0; itemIndex < Model.Wishitems.Count; itemIndex++)
{
@Html.EditorFor(item => Model.Wishitems.ToList()[itemIndex])
}
</table>
<p>
<input type="submit" value="Save" />
</p>
}
Run Code Online (Sandbox Code Playgroud)
@model Sandbox.Models.Wishitem
<tr>
<td>
@Html.HiddenFor(item=>item.WishitemId)
@Html.TextBoxFor(item => item.Quantity)
@Html.ValidationMessageFor(item => item.Quantity)
</td>
<td>
@Html.TextBoxFor(item => item.Name)
@Html.ValidationMessageFor(item => item.Name)
</td>
</tr>
Run Code Online (Sandbox Code Playgroud)
上面的设置生成一个页面,其中包含"父"愿望清单模型的标准输入元素:
<input class="text-box single-line" id="Name" name="Name" type="text" value="MyWishlist" />
Run Code Online (Sandbox Code Playgroud)
对于表中的'children'Wishitems,我们获得了索引输入元素:
<input data-val="true" data-val-number="The field Quantity must be a number." data-val-required="The Quantity field is required." name="[0].Quantity" type="text" value="42" />
<input name="[0].Name" type="text" value="Unicorns" />
Run Code Online (Sandbox Code Playgroud)
这导致了一个Wishlist wishlist带有空.Wishitems属性的POST参数.
POST处理程序([HttpPost] public ActionResult Edit(Wishlist wishlist, ICollection<Wishitem> wishitems))的替代签名仍然是空的wishlist.Wishitems,但让我访问(可能已修改)wishitems.
在第二种情况下,我可以做一些自定义绑定.例如(不是我在职业生涯中见过的最优雅的代码):
[HttpPost]
public ActionResult Edit(Wishlist editedList, ICollection<Wishitem> editedItems)
{
var wishlist = db.Wishlists.Find(editedList.WishListId);
if (wishlist == null) { return HttpNotFound(); }
if (ModelState.IsValid)
{
UpdateModel(wishlist);
foreach (var editedItem in editedItems)
{
var wishitem = wishlist.Wishitems.Where(wi => wi.WishitemId == editedItem.WishitemId).Single();
if (wishitem != null)
{
wishitem.Name = editedItem.Name;
wishitem.Quantity = editedItem.Quantity;
}
}
db.SaveChanges();
return View(wishlist);
}
else
{
editedList.Wishitems = editedItems;
return View(editedList);
}
}
Run Code Online (Sandbox Code Playgroud)
我希望有一种方法可以将所有POSTed数据放在一个结构化对象中,例如:
[HttpPost]
public ActionResult Edit(Wishlist wishlist) { /* ...Save the wishlist... */ }
Run Code Online (Sandbox Code Playgroud)
与wishlist.Wishitems填充有(潜在修改)项
或者更优雅的方式让我处理数据的合并,如果我的控制器必须单独接收它们.就像是
[HttpPost]
public ActionResult Edit(Wishlist editedList, ICollection<Wishitem> editedItems)
{
var wishlist = db.Wishlists.Find(editedList.WishListId);
if (wishlist == null) { return HttpNotFound(); }
if (ModelState.IsValid)
{
UpdateModel(wishlist);
/* and now wishlist.Wishitems has been updated with the data from the Form (aka: editedItems) */
db.SaveChanges();
return View(wishlist);
}
/* ...Etc etc... */
}
Run Code Online (Sandbox Code Playgroud)
提示,提示,想法?
"ASP.NET MVC3入门" 涵盖了基础知识,但不涉及模型关系
"使用MVC入门EF"
an-asp-net-mvc-application特别是第6部分展示了如何处理模型之间的一些关系.但是,本教程使用FormCollectionPOST处理程序的参数,而不是自动模型绑定.换句话说:[HttpPost] public ActionResult Edit(int id,FormCollection formCollection)而不是[HttpPost]行的内容公共ActionResult编辑(InstructorAndCoursesViewModel viewModel)此外,还表示与给定教师关联的课程列表(在UI)作为一组具有相同名称的复选框(导致string[]POST处理程序的参数),与我正在查看的场景不完全相同.
"编辑一个可变长度列表,ASP.NET MVC2风格" 基于MVC2(所以我想知道它是否仍然描述了我们拥有MVC3的最佳选择).不可否认,我还没有(还)处理从名单中插入和/或删除儿童模型的问题.此外,这个解决方案:
"用于模型绑定到数组,列表,集合,词典的ASP.NET线格式" Scott Hanselman的帖子是MVC应用程序中绑定到列表主题的最引用的参考文章之一.但是,他只是简单地描述框架采用的命名约定,并用于生成与您的操作方法匹配的对象(请注意文章没有生成页面的示例,然后将数据提交到所描述的操作之一).如果我们必须自己生成HTML,这是很好的信息.我们必须吗?
"模型绑定到列表"
另一个顶级参考,由Phil Haack.它有一些与上面Hansleman帖子相同的信息,但也向我们展示了我们可以在循环(for (int i = 0; i < 3; i++) { Html.TextBoxFor(m => m[i].Title) })或编辑器模板(Html.EditorFor(m=>m[i]))中使用HtmlHelpers .但是,使用此方法,编辑器模板生成的HTML将不包含任何特定前缀(例如:输入元素的名称和ID将采用以下形式[index].FieldName:[0].Quantity,或[1].Name).这在示例中可能或可能不是关键,但在我的实际应用中可能是一个问题,其中不同的"并行"子列表可能出现在同一视图中.
| 归档时间: |
|
| 查看次数: |
5405 次 |
| 最近记录: |