These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 
Author Message
 Post subject: What is the best practice in managing session for NHibernate
PostPosted: Thu Oct 23, 2008 8:33 am 
Newbie

Joined: Thu Oct 23, 2008 8:28 am
Posts: 2
ISession is a very important concept in NHibernate since it actually handles connection, transaction and others, thus how an application manages the session can at an impressive level affects the performance.
Basically there are 2 ways to manage the session:
1.Session per method
2.Session per conversation

Session per method is common in n-tier architecture where each operation method has its own session created from SessionFactory, the method finishes its operations using the session, flushes the session and dispose it, however, open sessions and transaction frequently may reduce the performance, moreover, each method may invoke other methods which have their own session, in such situation there are “nested” sessions and transaction and it may cause a distributed transaction, when it happens, MSDTC is required on windows OS and it makes a great fall of performance.

The second method to manage session, I called session per conversation may in some way provides better performance but on the other side it can bring disaster to your application.
Here by conversation I mean a whole scope of user request, it may be an asp.net request life-cycle from BeginRequest to EndRequest, here we initialize a session in BeginRequest event, use it all cross the life-cycle and dispose it in EndRequest.
In this way the session is reused greatly, and everything seams good, but once an exception occurred in session operation, all goodness brakes, here I have a little code to provide a classic case in which the “session per conversation” will cause a “never flush successfully” problem:
First we have our database like below
Code:
CREATE DATABASE TestFromGrayZhang;

GO

USE TestFromGrayZhang;

GO

CREATE TABLE TestUser (
   ID INT IDENTITY PRIMARY KEY,
   [Name] NVARCHAR(50) NOT NULL
);

GO

INSERT INTO TestUser VALUES ('AA');
INSERT INTO TestUser VALUES ('BB');
INSERT INTO TestUser VALUES ('CC');


Then the entity class and mapping file:
Code:
public class User
{
    public virtual int ID
    {
        get;
        set;
    }

    public virtual string Name
    {
        get;
        set;
    }
}


Code:
<?xml version="1.0"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="GDev.Test.Cmd"
    namespace="GDev.Test.Cmd">

  <class name="User" table="[TestUser]">

    <id name="ID" type="Int32" column="ID" unsaved-value="0">
      <generator class="native"/>
    </id>

    <property name="Name" not-null="true"/>

  </class>

</hibernate-mapping>


I have a method called UpdateUser which will update a user using a session:
Code:
public static void UpdateUser(User user, ISession session)
{
    using (ITransaction transaction = session.BeginTransaction())
    {
        try
        {
            session.Update(user);
            transaction.Commit();
        }
        catch (Exception)
        {
            transaction.Rollback();
            session.Evict(user);
            throw;
        }
    }
}


Then in the Main method I build the SessionFactory, create a singleton session to use:
Code:
ISessionFactory f;
Configuration config = new Configuration();
config.AddAssembly("GDev.Test.Cmd");
f = config.BuildSessionFactory();

//Session per conversation
ISession session = f.OpenSession();


I get 2 users from the session and it works well:
Code:
User user1 = session.Get<User>(1);
User user2 = session.Get<User>(2);


I update the name of 1st user to null, which is not allowed and update it, sure an exception is thrown:
Code:
user1.Name = null; //Null is not allowed for property name
try
{
    UpdateUser(user1, session); //The update method will throw exception
}
catch (Exception ex)
{
    Console.WriteLine("Error in updating the 1st user");
    Console.WriteLine(ex.Message);
}


Then I update the 2nd user to a valid name:
Code:
user2.Name = "XX"; //This is allowed
try
{
    UpdateUser(user2, session); //But due to previous update error, this update can never be commited
}
catch (Exception ex)
{
    Console.WriteLine("Error in updating the 2nd user");
    Console.WriteLine(ex.Message);
}


But the session still needs to update the 1st user because the name property has changed, so it can never complete the update statement and therefore user2 can never be updated correctly

So which management method should I use, and how to avoid the defect of the “session per conversation” method?


[/code]


Top
 Profile  
 
 Post subject:
PostPosted: Thu Oct 23, 2008 10:10 am 
Newbie

Joined: Wed Sep 05, 2007 12:22 pm
Posts: 8
I take it your design is for a Windows App and not a Web App?


Top
 Profile  
 
 Post subject:
PostPosted: Fri Oct 24, 2008 1:05 am 
Newbie

Joined: Thu Oct 23, 2008 8:28 am
Posts: 2
It is actually for a Web Application, here by "conversation" I mean a post back or a fresh request from BeginRequest to EndRequest, the ASP.NET Webform module allows to make a singleton per HttpContext scope


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.