views:

50

answers:

1

This works:

public ActionResult Save(int id, string name)
{
    var profile = _profileRepository.GetById(id);
    profile.Name = name;
    _profileRepository.Save(profile); //this calls SaveOrUpdate()

    //session.Commit() gets called in global.asax on Application_EndRequest()
    //profile.Name is changed in the database
}

Since my actual problem is more complicated than this simple example, I'd like to get the profile from the repo, use TryUpdateModel on the profile to update any changes, and then save. However, when I introduce TryUpdateModel into the mix, it fails with a NonUniqueObjectException (a different object with the same identifier value was already associated with the session):

public ActionResult Save(int id)
{
    var profile = _profileRepository.GetById(id); 
    TryUpdateModel(profile); //this works from the looks of it
    _profileRepository.Save(profile); //this also appears to work;

    //fails on session.Commit()
    //nothing changed in database
}

A "different" object with the same identifier value?? It looks as though TryUpdateModel is disconnecting my profile object from the session. Any thoughts?

+1  A: 

The first example would work because you are updating the same object retrieved through the NHibernate Session.

The second example has the potential to fail because TryUpdateModel() may replace the properties of your profile object (if matching ValueProvider data exists). If by chance you are posting back data for one of these properties including the Id, the TryUpdateModel() method might replace one of the objects originally retrieved through the NHibernate Session. When you attempt to save the profile, NHibernate is going to recognize that you didn't edit the original object, but are attempting to save a different object with the exact same Id. This would result in a NonUniqueObjectException.

To resolve this issue, you should ensure that you are updating the values of the original entities retrieved from Session. I would recommend that you avoid using the DefaultModelBinder directly against entities from your domain which you expect to have change tracking performed for.

Derek Greer