I have a model binding problem in my ASP.NET MVC 2 RC application that uses NHibernate to access data. We are trying to create an application in Ruby on Rails and have a very simple architecture where domain objects are used completely from the database to the view.
An application has a pair of domain objects that can be illustrated by the following two classes:
public class Product { ... public Category Category { get; set; } } public class Category { public int Id { get; set; } public string Name { get; set; } }
In a view in which the edit form has the following operator for displaying a drop-down list:
<%= Html.DropDownListFor(model => model.Category.Id, new SelectList(ViewData["categories"] as IList<Category>, "Id", "Name"), "-- Select Category --" ) %>
Please ignore the use of "unprinted" view data to store a collection of categories.
The action method receiving the form message is similar to the following. Note that the TransactionFilter attribute adds an NHibernate transaction transaction and completes the transaction if no exceptions occur and the validation is successful.
[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); }
My problem is that product.Category.Id is set with the value selected in the form, for example. Category.Id = "2". Using model bindings by default results in an NHibernate exception of the following type:
identifier of an instance of Name.Space.Entities.Category was altered from 4 to 2
This makes a lot of sense, since the product already has a category, and only the primary key of this existing category is changed. Instead, another instance of the category should be assigned.
I think a custom ModelBinder can be created to solve this problem, but is there an easier way to make this work? Can (and should) domain objects be modified to handle this?