Transparant Lazy Loading in Long Sessions

36 views
Skip to first unread message

FrederikGheysels

unread,
Nov 7, 2008, 8:18:49 AM11/7/08
to nhusers
I am using NHibernate in a WinForms application.
In this application, I make use of 'long sessions'; consider that I
have an ISession that is kept around as long as my Form is open.

That is:
I load an object using this Session when the form is opened.
When the form is being closed, I check if I have to save the object,
and if so, I save it using the same session.

During 'user think time', I disconnect the Session, so that the DB
connection is not kept open for a long period of time.

The issue that I now have, is that my object contains a collection
which is lazy loaded.
Since I disconnect my session once the object has been loaded, I get
an exception offcourse when I want to access the collection of that
object. (I do not always need this collection).

Therefore, when I need to access the collection, I explicitly
reconnect the Session, and disconnect it afterwards. Offcourse, this
is not very 'transparant' IMHO.
It would be nice if there would be some way to reconnect the session
implicitly; the client should not even know that the collection that I
want to retrieve, is a lazyloaded collection.

I've tried creating an Intercepter, in where I've overriden the
SetSession, Load and Instantiate methods. In this way, I thought that
I could reconnect the session each time the Load or Instantiate
methods were invoked, and when I saw that the session was
disconnected, I could reconnect the session.
But, this doesn't work.

Another option, would be that I keep my Session connected during 'user
think time', but IMHO , this is not a viable option; one never knows
how long the Form (and therefore the session) will be kept open, and
connected to the DB.

Is there any other way on how I could make this a bit more
transparant ?
Maybe it is an idea to add a method to the Interceptor which is
invoked each time something is being lazy loaded (just before it is
lazy loaded) ?

Ayende Rahien

unread,
Nov 7, 2008, 8:23:19 AM11/7/08
to nhu...@googlegroups.com
Don't disconnect the session NH will take care of closing/opening the connection to optimize it to minimal usage time.

Fabio Maulo

unread,
Nov 7, 2008, 8:35:24 AM11/7/08
to nhu...@googlegroups.com
apply conversation pattern. An example is available in uNhAddIns (it need some additional work to support ambient-transaction).
Begin/Commit the transaction and let NH to deal with the connection.

2008/11/7 FrederikGheysels <frederik...@pandora.be>



--
Fabio Maulo

FrederikGheysels

unread,
Nov 7, 2008, 9:03:41 AM11/7/08
to nhusers
How will it do that then, if I may ask ?
I mean, suppose I open a session, load an object from the DB and do
not disconnect the session.
Then, the object is loaded, the user leaves for lunch for instance,
He comes back, does some other changes, and wants to persist his work.
When will NHibernate disconnect the session ?

Does the 'connection.release-mode' configuration value also affects
this behaviour ?

On Nov 7, 2:23 pm, "Ayende Rahien" <aye...@ayende.com> wrote:
> Don't disconnect the session NH will take care of closing/opening the
> connection to optimize it to minimal usage time.
>
> On Fri, Nov 7, 2008 at 3:18 PM, FrederikGheysels <
>

Ayende Rahien

unread,
Nov 7, 2008, 9:09:47 AM11/7/08
to nhu...@googlegroups.com
Load()
 -- open connection 
 -- execute sql
 -- close connection

Save()
  -- open connection 
  -- execute sql
  -- close connection

Fabio Maulo

unread,
Nov 7, 2008, 9:13:53 AM11/7/08
to nhu...@googlegroups.com
2008/11/7 FrederikGheysels <frederik...@pandora.be>


How will it do that then, if I may ask ?
I mean, suppose I open a session, load an object from the DB and do
not disconnect the session.
Then, the object is loaded, the user leaves for lunch for instance,
He comes back, does some other changes, and wants to persist his work.
When will NHibernate disconnect the session ?

There is not a 1:1 relation of the NH-Session with the Connection.
How NH manage the connection depend from various things. In general you can be sure that NH close the connection after a transaction commit/rollback. Obviously... you must take care about the transaction-life-cycle.

Does the 'connection.release-mode' configuration value also affects
this behaviour ?

Leave it as default.

--
Fabio Maulo

FrederikGheysels

unread,
Nov 7, 2008, 10:01:28 AM11/7/08
to nhusers
On 7 nov, 15:13, "Fabio Maulo" <fabioma...@gmail.com> wrote:
> There is not a 1:1 relation of the NH-Session with the Connection.
> How NH manage the connection depend from various things. In general you can
> be sure that NH close the connection after a transaction
> commit/rollback. Obviously... you must take care about the
> transaction-life-cycle.
>
> Fabio Maulo

I already do that. :)
context is king. :)

FrederikGheysels

unread,
Nov 7, 2008, 10:30:11 AM11/7/08
to nhusers
I must be doing something wrong I think.

I've left the connection release mode to the default setting.
I do this:
Start Transaction
Get entity
Commit Transaction

I expect that the Session is disconnected after the Commit
Transaction, but it is not. The Session is still connected.

The ConnectionRelease mode is set to: AfterTransaction
After I've committed the Transaction, Session.IsConnected returns true.

Fabio Maulo

unread,
Nov 7, 2008, 10:33:32 AM11/7/08
to nhu...@googlegroups.com
How you are checking it?
You can't use NH to check the connection state because NH give you an open-connection each time you access to the connection trough NH.
We talk about this matter in this list some months ago.

2008/11/7 FrederikGheysels <frederik...@pandora.be>



--
Fabio Maulo

Fabio Maulo

unread,
Nov 7, 2008, 10:36:25 AM11/7/08
to nhu...@googlegroups.com
2008/11/7 FrederikGheysels <frederik...@pandora.be>

I expect that the Session is disconnected after the Commit
Transaction, but it is not.  The Session is still connected.

Trust us ;)
and don't worry about it.

--
Fabio Maulo

Ayende Rahien

unread,
Nov 7, 2008, 10:36:34 AM11/7/08
to nhu...@googlegroups.com
You need to do the check using the DB tool.
NH maintains the abstraction that the session always have an open connection, even when it has to explicitly create a new connection on the fly for you

Roger Kratz

unread,
Nov 7, 2008, 10:56:49 AM11/7/08
to nhu...@googlegroups.com
As Fabio stated, this has been discussed before. I had the same "issue".

Here's the thread
http://groups.google.com/group/nhusers/browse_thread/thread/7b2c12e02bb604c4/3cc9cdef8cd1a7fb?hl=en&lnk=gst

/Roger

FrederikGheysels

unread,
Nov 7, 2008, 10:59:44 AM11/7/08
to nhusers
On 7 nov, 16:36, "Fabio Maulo" <fabioma...@gmail.com> wrote:
> 2008/11/7 FrederikGheysels <frederik.gheys...@pandora.be>
>
> > I expect that the Session is disconnected after the Commit
> > Transaction, but it is not.  The Session is still connected.
>
> Trust us ;)
> and don't worry about it.
>
> --
> Fabio Maulo

Please allow me to be a bit critical :)

When Ayende says that NH maintains the abstraction that the session
always has an open connection, then this also implies that the
IsConnected property of the ISession should always return true.
(Then, I wonder: what's the use of this property ) ?

I've also done a little test:

using( UnitOfWork uow =
UnitOfWorkFactory.Instance.CreateUnitOfWork () )
{
ISession s = uow.Session;

Assert.IsTrue (s.IsOpen, "Session is expected to be
open");
Assert.IsTrue (s.IsConnected, "Session is expected to
be connected");
Assert.AreEqual
(s.SessionFactory.Settings.ConnectionReleaseMode,
ConnectionReleaseMode.AfterTransaction,
"ConnectionReleaseMode is expected to
be AfterTransaction");
Assert.AreEqual (s.FlushMode, FlushMode.Auto,
"FlushMode must be Auto");

ITransaction tx = s.BeginTransaction
();

tx.Commit ();

Assert.IsFalse (s.IsConnected, "Session should be
disconnected");
}

This test fails on the last Assert.
I've also checked the number of connections using the SQL Server
sp_who SP.
From the results of this SP, I learn that the connection to my DB is
kept open when the Transaction has been committed ...

FrederikGheysels

unread,
Nov 7, 2008, 11:15:33 AM11/7/08
to nhusers
Hmm, but in NHibernate source I indeed see that the connection is
closed.

if (IsAfterTransactionRelease)
{
AggressiveRelease();
}
else if (IsAggressiveRelease && batcher.HasOpenResources)
{
log.Info("forcing batcher resource cleanup on transaction
completion; forgot to close ScrollableResults/Enumerable?");
batcher.CloseCommands();
AggressiveRelease();
}
else if (IsOnCloseRelease)
{
// log a message about potential connection leaks
log.Debug(
"transaction completed on session with on_close connection
release mode; be sure to close the session to release ADO.Net
resources!");
}
transaction = null;

where AggressiveRelease closes the connection ...

So, allow me to be a bit confused here.

On 7 nov, 16:59, FrederikGheysels <frederik.gheys...@pandora.be>
wrote:

Fabio Maulo

unread,
Nov 7, 2008, 11:26:35 AM11/7/08
to nhu...@googlegroups.com
2008/11/7 FrederikGheysels <frederik...@pandora.be>


So, allow me to be a bit confused here.

For that I said : Trust us ;)

When Ayende and I said the same, you can be sure that everything are working as we have said.

about session.IsConnected you must remember that you can take the control of the connection in various ways but... don't make you life so complicated ;)

--
Fabio Maulo

Sean Carpenter

unread,
Nov 7, 2008, 11:35:48 AM11/7/08
to nhu...@googlegroups.com
sp_who can't be used to check if the connection is still open since ADO.Net connection pooling will actually keep the underlying connection open even after it is closed from user code.  You can trust that it's available to be used by a different Session, so it is "closed" from the application's point of view.

Sean Carpenter

FrederikGheysels

unread,
Nov 7, 2008, 4:20:18 PM11/7/08
to nhusers
Then, what is a good way to see whether the connection is really
closed ?
Even if I want to detach my DB (while the session is still open, but
the transaction has been committed), I see that there is still an
active connection to the DB.

I'm sorry that I am a bit ... persistent ... Fabio, but I really want
to see it with my own eyes. :)

When I explicitly disable connection pooling, I can indeed see that
the number of connections to my DB decreases. (I've checked the
performance counters).
When I do not disable pooling, I do not see the number of connections
decrease.


On 7 nov, 17:35, "Sean Carpenter" <stcarpen...@gmail.com> wrote:
> sp_who can't be used to check if the connection is still open since ADO.Net
> connection pooling will actually keep the underlying connection open even
> after it is closed from user code.  You can trust that it's available to be
> used by a different Session, so it is "closed" from the application's point
> of view.
> Sean Carpenter
>
> On Fri, Nov 7, 2008 at 10:59 AM, FrederikGheysels <
>

Ayende Rahien

unread,
Nov 7, 2008, 4:24:25 PM11/7/08
to nhu...@googlegroups.com
Frederik,
Try to check the perf counters for the connection pooling.

christianacca

unread,
Nov 8, 2008, 5:00:28 AM11/8/08
to nhusers
Just looked at the source code myself.

So where does the connection get closed when an NHibernate tx is
committed? There is a method named CloseIfRequired that get's called
in a finally block in the AdoTransaction.Commit method. This method
looks like it should be closing the connection, but the body of the
method is commented out (I'm looking at NHibernate vs in
Rhino.Commons)

I'm obviously not a trusting kinda guy ;-)

Christian
PS. This has already been mentioned here: http://forum.hibernate.org/viewtopic.php?p=2399194#2399194

On Nov 7, 9:24 pm, "Ayende Rahien" <aye...@ayende.com> wrote:
> Frederik,Try to check the perf counters for the connection pooling.
>
> On Fri, Nov 7, 2008 at 11:20 PM, FrederikGheysels <
>

Fabio Maulo

unread,
Nov 8, 2008, 6:28:01 AM11/8/08
to nhu...@googlegroups.com
2008/11/8 christianacca <christian...@btinternet.com>

 (I'm looking at NHibernate vs in
Rhino.Commons)

What is that ?
--
Fabio Maulo

Fabio Maulo

unread,
Nov 8, 2008, 7:05:45 AM11/8/08
to nhu...@googlegroups.com
2008/11/8 christianacca <christian...@btinternet.com>


I'm obviously not a trusting kinda guy ;-)

I would like to leave you with all your doubt for long time, especially because your are sure that you are looking in the right place.
What is clear is that you don't know that NH allow you to inject your IConnectionProvider trough configuration and do what you want with the connection.
BTW for curious people :
<logger name="NHibernate.Connection.ConnectionProvider">
<level value="DEBUG" />
</logger>

log.Debug("Opening Session and transaction.");
using (ISession session = OpenSession())
using (ITransaction tx = session.BeginTransaction())
{
log.Debug("Save1.");
session.Save(john);

log.Debug("Going to commit.");
tx.Commit();
log.Debug("Committed.");
}
log.Debug("Session closed.");

The output is:
Fixture:30 - Save1.
Fixture:37 - Going to commit.
ConnectionProvider:28 - Closing connection
Fixture:39 - Committed.
Fixture:41 - Session closed.

When you take a look inside NH code is very important to know where look... believe me it is not so easy.

Ah... next time : Trust us!! ;-)
--
Fabio Maulo

christianacca

unread,
Nov 10, 2008, 12:41:10 PM11/10/08
to nhusers
Thanks for correcting me Fabio :-)

And also for the tip about knowing where to look!

C

On Nov 8, 12:05 pm, "Fabio Maulo" <fabioma...@gmail.com> wrote:
> 2008/11/8 christianacca <christian.crowhu...@btinternet.com>
>
>
>
> > I'm obviously not a trusting kinda guy ;-)
>
> I would like to leave you with all your doubt for long time, especially
> because your are sure that you are looking in the right place.What is clear

FrederikGheysels

unread,
Nov 12, 2008, 4:38:24 AM11/12/08
to nhusers
Ok thx for the replies, one more question. :)

I still do not understand something:
- when I explicitely call 'Disconnect' to close the DB connection
(which I understand is obsolete), NHibernate is not able (or just
doesn't) reconnect implicitely when necessary.
- when I do not call Disconnect, but use the 'after_transaction'
connection-release mode, NH disconnects the session from the DB after
the transaction has completed. When NH needs to access the DB again,
it reconnects implicitely. (For instance, in a lazy-loading case: I
retrieve an object within a transaction. When the transaction is
committed, the connection is closed. A few seconds later, I need the
lazy collection: NHibernate connects the session, retrieves the
collection and disconnects the session again (I'm not sure about this
last one :) ).

Why is this behaviour different ?
Reply all
Reply to author
Forward
0 new messages