Luca Petrini
Luca Petrini

Reputation: 1745

NHibernate stateless insert behavior

I would like to have an opinion on a behavior that I found when I use INSERT command with stateless session on NHibernate (NB. I use NHibernate 2.1.2)

The case is this

//STATEFULL SESSION
var session = sessionFactory.OpenSession()
using(var transaction = session.BeginTransaction()){
   var entity = new MyEntityType();
   entity.Id = 1;

   session.Save(entity);

   var entity2 = session.Get<MyEntityType>(1);  
   //OK! It returns saved entity...as I expect

   transaction.Commit();
}

but...on stateless session, the behavior changes...

//STATELESS SESSION
var session = sessionFactory.OpenStatelessSession()
using(var transaction = session.BeginTransaction()){
   var entity = new MyEntityType();
   entity.Id = 1;

   session.Insert(entity);

   var entity2 = session.Get<MyEntityType>(1);  
   //entity2 IS NULL!!! Why?

   transaction.Commit();
}

My question is...how can I check if I already inserted an item on transaction scope of stateless session?

Upvotes: 4

Views: 3046

Answers (1)

Fr&#233;d&#233;ric
Fr&#233;d&#233;ric

Reputation: 9854

Well, stateless is... stateless. So there is no session cache for yielding you your inserted entity back from memory.

Now, why does it not get read in database? Because it is not yet there!

Most likely you have batching enabled (adonet.batch_size xml configuration parameter, or by code Environment.BatchSize configuration property, or by not having disabled it through IStatelessSession.SetBatchSize(int) while it is enabled at session factory level). With batching enabled, if your NHibernate database driver supports it, the DML operations are batched together as much as possible, up to the configured batch size, then flushed to database.

So such a flush with a stateless session can occur:

  • If "batch size" count of operations to perform is reached.
  • If a transaction is committed.
  • If another DML query, differing not only by its parameters values, is done.
    (In your case, such as inserting another kind of entity after your insert, or updating or deleting any kind of entity after your insert.)
  • By explicitly flushing the batcher, tapping the internal session interface.
    s.GetSessionImplementation().Flush();

If you want to have your Insert immediately sent to the database, disable batching. Setting it to 0 will disable it.

But why are you using a stateless session in the first place? Likely for inserting lots of entities in an efficient way. In such case, disabling batching will deserve your purpose.

So you may instead reach the internal session interface, exposed by the session GetSessionImplementation() method, and explicitly Flush it. But well, directly calling internals may yield undefined behavior, so this is not a recommended practice.

Upvotes: 5

Related Questions