Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NHibernate ISession.Save() - Why is this persisting my entities immediately?

I am creating a large number of entities with NHibernate, attaching them to my ISession, and then using a transaction to commit my changes to the database. Code sample is below:

ISession _context = SessionProvider.OpenSession();

//Create new entities
for(int i=0; i<100; i++)
{
    MyEntity entity = new MyEntity(i);

    //Attach new entity to the context
    _context.Save(entity);
}

//Persist all changes to the database
using(var tx = _context.BeginTransaction())
{
    //Flush the session
    tx.Commit();
}

I was under the impression that the line _context.Save() simply makes the ISession aware of the new entity, but that no changes are persisted to the database until I Flush the session via the line tx.Commit().

What I've observed though, is that the database gets a new entity every time I call _context.Save(). I end up with too many individual calls to the database as a result.

Does anyone know why ISession.Save() is automatically persisting changes? Have I misunderstood something about how NHibernate behaves? Thanks.

***EDIT - Just to clarify (in light of the two suggested answers) - my problem here is that the database IS getting updated as soon as I call _context.Save(). I don't expect this to happen. I expect nothing to be inserted into the database until I call tx.Commit(). Neither of the two suggested answers so far helps with this unfortunately.

Some good information on identity generators can be found here

like image 846
JMc Avatar asked Dec 04 '22 21:12

JMc


2 Answers

Try:

using(Session _context = SessionProvider.OpenSession())
using(var tx = _context.BeginTransaction())
{
    //Create new entities
    for(int i=0; i<100; i++)
    {
        MyEntity entity = new MyEntity(i);

        //Attach new entity to the context
        _context.Save(entity);
    }

    //Flush the session
    tx.Commit();
}
like image 138
StuffHappens Avatar answered Jan 06 '23 09:01

StuffHappens


Which identity generator are you using? If you are using post-insert generators like MSSQL/MySQL's Identity or Oracle's sequence to generate the value of your Id fields, that is your problem.

From NHibernate POID Generators Revealed:

Post insert generators, as the name suggest, assigns the id’s after the entity is stored in the database. A select statement is executed against database. They have many drawbacks, and in my opinion they must be used only on brownfield projects. Those generators are what WE DO NOT SUGGEST as NH Team.

Some of the drawbacks are the following

  1. Unit Of Work is broken with the use of those strategies. It doesn’t matter if you’re using FlushMode.Commit, each Save results in an insert statement against DB. As a best practice, we should defer insertions to the commit, but using a post insert generator makes it commit on save (which is what UoW doesn’t do).
  2. Those strategies nullify batcher, you can’t take the advantage of sending multiple queries at once(as it must go to database at the time of Save)
like image 31
rebelliard Avatar answered Jan 06 '23 10:01

rebelliard