4

我在使用 NHibernate 进行数据访问的 ASP.NET MVC 2 RC 应用程序中的模型绑定存在问题。我们正在尝试以 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 --" ) %>

请忽略使用“非类型化”视图数据来保存类别集合。

接收表单 post 的操作方法类似于以下内容。请注意,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 来处理这个问题,但是有没有更简单的方法来完成这个工作?可以(并且应该)修改域实体来处理这个问题吗?

4

3 回答 3

2

我通过更改以下行解决了编辑页面上组合框的类似问题

@Html.DropDownListFor(x => x.Employee.Id, new SelectList(ViewBag.Employees, "Id", "DisplayName"))

经过

@Html.DropDownListFor(x => x.Employee, new SelectList(ViewBag.Employees, "Id", "DisplayName"))

所以我像布莱恩建议的那样删除了“.Id”。更改前,模型只包含员工的 Id,更改后,Binder 还将员工的所有详细信息加载到模型中。

于 2012-10-03T19:34:25.400 回答
0

我之前在 Linq to SQL 类中使用过类似的技术,没有任何问题。我认为您不需要为此定制 ModelBinder。UpdateModel 应该更新您传递给它的 Product 类 - 而不是附加到它的 Category 子类。检查 DropDownListFor 助手生成的 html。元素的名称是什么?它应该是 Products 表中外键字段的名称(例如“CategoryID”或“Product.CategoryID”而不是“Category.Id”)。如果是“Category.Id” - 尝试将 DropDownListFor 的第一个参数更改为“model => model.Category”或“model => model.CategoryID”(或任何外键字段)。

于 2010-01-18T02:37:57.143 回答
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;
}

我们只是告诉模型绑定器排除关联属性并手动处理它。不漂亮,但当时工作....

于 2011-06-08T12:32:37.497 回答