tags:

views:

1900

answers:

4

Does batch update command exist in NHibernate? As far as I am aware it doesn't. So what's the best way to handle this situation? I would like to do the following:

  1. Fetch a list of objects ( let's call them a list of users, List<User> ) from the database
  2. Change the properties of those objects, ( Users.Foreach(User=>User.Country="Antartica")
  3. Update each item back individually ( Users.Foreach(User=>NHibernate.Session.Update(User)).
  4. Call Session.Flush to update the database.

Is this a good approach? Will this resulted in a lot of round trip between my code and the database?

What do you think? Or is there a more elegant solution?

A: 

You don't need to update, nor flush:

IList<User> users = session.CreateQuery (...).List<User>;
users.Foreach(u=>u.Country="Antartica")
session.Transaction.Commit();

I think NHibernate writes a batch for all the changes.

The problem is, that your users need to be loaded into memory. If it gets a problem, you can still use native SQL using NHibernate. But until you didn't prove that it is a performance problem, stick with the nice solution.

Stefan Steinegger
This depends on the FlushMode. session.FlushMode = FlushMode.Never won't save without an explicit call to Flush(). Your code would work with FlushMode.Commit however
MPritch
+5  A: 

You can set the batch size for updates in the nhibernate config file.

<property name="hibernate.adonet.batch_size">16</property>

And you don't need to call Session.Update(User) there - just flush or commit a transaction and NHibernate will handle things for you.

EDIT: I was going to post a link to the relevant section of the nhibernate docs but the site is down - here's an old post from Ayende on the subject:

As to whether the use of NHibernate (or any ORM) here is a good approach, it depends on the context. If you are doing a one-off update of every row in a large table with a single value (like setting all users to the country 'Antarctica' (which is a continent, not a country by the way!), then you should probably use a sql UPDATE statement. If you are going to be updating several records at once with a country as part of your business logic in the general usage of your application, then using an ORM could be a more sensible method. This depends on the number of rows you are updating each time.

Perhaps the most sensible option here if you are not sure is to tweak the batch_size option in NHibernate and see how that works out. If the performance of the system is not acceptable then you might look at implementing a straight sql UPDATE statement in your code.

Steve Willcock
A: 

No it's not a good approach!

Native SQL is many times better for this sort of update.

UPDATE USERS SET COUNTRY = 'Antartica';

Just could not be simpler and the database engine will process this one hundred times more efficiently than row at a time Java code.

James Anderson
He's using NHibernate, that's .NET not Java :)
Steve Willcock
I am confused here: if your argument is valid then there should be no use of ORM because db engine will always process SQL code many times more efficiently than ORM code... am I right?
Ngu Soon Hui
Ngu, I have updated my answer to respond to your comment there.
Steve Willcock
Well ORM mapping is great for single object CRUD access to a database, you lose significant amounts of power and flexibility by not using native SQL.
James Anderson
See Martin's answer, you still can use your ORM, no need to steal from your employer and write ado.net code.
mxmissile
+7  A: 

I know I'm late to the party on this, but thought you may like to know this is now possible using HQL in NHibernate 2.1+

session.CreateQuery(@"update Users set Country = 'Antarctica'")
.ExecuteUpdate();
MPritch