我的ASP.NET MVC 2 RC应用程序中的模型绑定存在问题,该应用程序使用NHibernate进行数据访问。我们正在尝试以Ruby on Rails的方式构建应用程序,并且有一个非常简单的体系结构,其中域实体从数据库到视图一直使用。
该应用程序有几个域实体,可以通过以下两个类来说明:
public class Product {
...
public Category Category { get; set; }
}
public class Category {
public int Id { get; set; }
public string Name { get; set; }
}
在呈现编辑表单的视图中,显示下拉列表的语句如下:
<%= Html.DropDownListFor(model => model.Category.Id,
new SelectList(ViewData["categories"] as IList<Category>, "Id", "Name"),
"-- Select Category --" ) %>
请忽略使用“非类型”视图数据来保存类别集合。
接收表单帖子的操作方法类似于以下内容。请注意,TransactionFilter属性添加了NHibernate事务处理,并在没有异常发生且验证成功时提交事务。
[HttpPost]
[TransactionFilter]
public ActionResult Edit(int id, FormCollection collection) {
var product = _repository.Load(id);
// Update the product except the Id
UpdateModel(product, null, null, new[] {"Id"}, collection);
if (ModelState.IsValid) {
return RedirectToAction("Details", new {id});
}
return View(product);
}
我的问题是product.Category.Id是使用表单中选择的值设置的,例如Category.Id =“2”。使用默认模型绑定器会导致以下类型的NHibernate异常:
identifier of an instance of Name.Space.Entities.Category was altered from 4 to 2
这很有意义,因为产品已经分配了类别,并且只更改了现有类别的主键。应该已经分配了另一个类别实例。
我想可以创建一个自定义的ModelBinder来处理这个问题但是有一种更简单的方法可以使它工作吗?可以(并且应该)修改域实体来处理这个吗?
答案 0 :(得分:2)
我通过更改以下行来解决编辑页面上组合框的类似问题
@Html.DropDownListFor(x => x.Employee.Id, new SelectList(ViewBag.Employees, "Id", "DisplayName"))
通过
@Html.DropDownListFor(x => x.Employee, new SelectList(ViewBag.Employees, "Id", "DisplayName"))
所以我像Bryan建议的那样删除了'.Id'。在更改之前,模型仅包含Employee的Id,并且在更改之后,Binder还将员工的所有详细信息加载到模型中。
答案 1 :(得分:0)
我之前使用过Linq到SQL类的类似技术没有问题。我不认为你需要一个自定义的ModelBinder。 UpdateModel应该更新您传递给它的Product类 - 而不是附加到它的Category子类。检查DropDownListFor助手生成的html。元素的名称是什么?它应该是Products表中外键字段的名称(例如“CategoryID”或“Product.CategoryID”而不是“Category.Id”)。如果它是“Category.Id” - 尝试将DropDownListFor的第一个参数更改为“model =&gt; model.Category”或“model =&gt; model.CategoryID”(或任何外键字段)。这应该导致UpdateModel只更新Product类中的外键字段而不是Category类ID。
答案 2 :(得分:0)
我们当时选择的解决方案与此类似:
TryUpdateModel(product, null, null, new[] {"Category"}, collection);
int categoryId;
if (int.TryParse(collection["Category.Id"], NumberStyles.Integer, CultureInfo.InvariantCulture, out categoryId) && categoryId > 0) {
product.Category = _categoryRepository.Load(categoryId);
}
else {
product.Category = null;
}
我们只是告诉模型绑定器排除关联属性并手动处理它。不漂亮,但当时工作....