tags:

views:

268

answers:

5

I have a User object that has a Country object on it. I map this with a many-to-one tag in the User mapping file:

<many-to-one name="Country" column="CountryID" cascade="none"/>

How do I update a User's country?

At the moment my UI has a dropdown of countries and the ID of the new country is passed to the controller. The controller then sets the ID of the User's country from that value. So:

var user = session.Get<User>(userID);
user.Country.ID = Convert.ToInt32(Request.Form["Country_ID"]);

But when I call:

session.SaveOrUpdate(user);

I get an error saying that "identifier of an instance of Country was altered from 7 to 8". Presumably this is because the Country object is marked as dirty by NHibernate? I don't want to update the country object though, just the ID reference in the User. Is it possible to do it this way?

Thanks, Jon

A: 
var user = session.Get<User>(userID);
user.Country = session.Get<Country>(Convert.ToInt32(Request.Form["Country_ID"]));

You must retrieve the country from the database and then set it to the user

loraderon
A: 

Thanks Anders. Why do we need the extra overhead of first getting the object back when all we are doing is updating a reference to that object?

In reality our controller is automatically deserializing the request to the object. Is there no way we can tell NHibernate to ignore the updating of the country object and just update the user? I would have thought cascade="none" would have done that.

What happens if you have several many-to-one objects on a object that need to be updated? That is a lot of overhead to get them all back before saving.

JontyMC
Actually you don't necessarily need nhibernate to retrieve the data. There is a small difference between ISession's Load and Get. One of them works lazily the other retrieves immediately.
Min
+1  A: 

You can always get hold of the underlying connection and do the update manually.

http://www.darkside.co.za/archive/2008/03/03/castle-activerecord-get-the-underlying-database-connection.aspx

loraderon
A: 

That would really negate the whole purpose of using an ORM in the first place, wouldn't it? What is the normal pattern for updating child objects like this? Surely it is a very common scenario. Is it to load every single one up:

var user = session.Get<User>(userID);
user.Country = session.Get<Country>(Convert.ToInt32(Request.Form["Country_ID"]));
user.Manager = session.Get<User>(Convert.ToInt32(Request.Form["Manager_ID"]));
user.State = session.Get<State>(Convert.ToInt32(Request.Form["State _ID"]));
user.Region = session.Get<Region>(Convert.ToInt32(Request.Form["State _ID"]));

Do we really need to make an extra database call for every child object (event though those objects aren't being updated)?

At the moment we have:

var ds = new NameValueDeserializer();
var entity = session.Get<TEntity>(entityID);
ds.Deserialize(entity, form);
session.Update(entity);

So this works generically for all entities. Having to specifically load up child objects to save the entity would be an unnecessary coding overhead (as well as making extra database calls).

Is there no way round this in configuration, mappings, interceptors, etc? Does anyone know why Hibernate has taken this design decision?

JontyMC
A: 

You should probably take this discussion to the NHibernate users group.

http://groups.google.com/group/nhusers

loraderon