NHibernate, Part 3 of xxx: NHibernate Session Management

Continuing my rant about NHibernate being a whole lot of stuff to learn, it's also somewhat difficult to know how to actually do things the “right way”. 

A big one for me was trying to figure out the best way to manage NHibernate sessions from an ASP.NET application.  If you were doing a Windows Forms application with NHibernate, it would be pretty easy to manage the session.  You'd open the session and probably put it in a static variable somewhere. 

Well, that kinda doesn't really work out so well for an ASP.NET application because that static variable is a Singleton to the app domain so it'll be shared across all requests.  Sounds like a threading nightmare waiting to happen. 

Then there's the option of putting the NHibernate session into the ASP.NET Session.  That's stinky because it could be open for a really long time and there isn't really any bulletproof way to kill the NHibernate session if the ASP.NET Session gets abandoned or otherwise shut down. 

And then there's thread local storage blah blah blah that doesn't work out well either for some reason blah blah blah.

Whatever.  Bottom line.  There are a whole mess of options that stink and no real rock-solid consensus on the news groups about what to do.  There's some agreement that opening up an NHibernate session for every web request will work but it took some digging to find that.  There was some sample code but not a complete working example. 

So.  It's not fantastic but it's something.  I started writing a bug tracker sample application as a proof of concept using NHibernate.  http://www.benday.com/temp/BugTrackerNHibernateSample.zip  It has a ASP.NET user interface and a Windows Forms user interface.  I've included a backup of my “bugs“ database. 

The key thing to look at is the NHibernateHttpModule in Com.Benday.BugTracker.DataAccess and how it gets registered in web.config.  This module gets loaded and creates an NHibernate session that exists for the duration of the http web request.  I based this largely (translation: entirely) on Ed Courtenay's code that he posted at http://sourceforge.net/forum/message.php?msg_id=2847509.  I think it works pretty well. 

Feel free to critique the approach.  I know that what I'm doing with NHibernate probably isn't perfect.

-Ben

FYI, other posts on NHibernate are available here.

posted @ Wednesday, March 16, 2005 11:55 AM

Print

Comments on this entry:

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by liz at 3/16/2005 3:16 PM
Gravatar
omg, you think MY blog is boring???

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by Hazem Torab at 4/19/2005 4:15 AM
Gravatar
I am using the same way in managing the sessions and it's perfect

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by Ben Scheirman at 4/28/2005 10:30 AM
Gravatar
I just blogged about this last night, lol. Glad to see that other minds are on the issue. I have yet to see the actual implementation, but what if we want to abstract NHibernate away from the UI? Doesn't this couple the UI code with NHibernate code?

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by Benjamin Day at 4/28/2005 10:41 AM
Gravatar
Actually, I don't think that UI coupling is an that much of an issue. In my sample app, if you look at NHibernateHttpModule.cs in the DataAccess assembly it just checks to see if HttpContext.Current is null. If it's null, it uses a static and ignores all the HttpContext stuff.

It's not fantastic to have the DataAccess layer "aware" of the UI implementation but the coupling is still pretty loose and UI doesn't know anything about the DataAccess implementation.

-Ben

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by Shawn at 5/25/2005 10:24 AM
Gravatar
The session can be opened per request, unless you are editing, then it makes sense to hold it for the duration of the edit process. It does make sense though to keep the session factory around, this becomes important if you intend on using a 2nd level cache like the one supplied in NHibernate Contrib.

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by Ben Scheirman at 5/25/2005 5:38 PM
Gravatar
I ran into an issue with this today, and it's quite strange. You and I discussed my implementation (which was not far off from yours), but I'll briefly describe it real quick:

Session-per-request pattern, using an HttpModule to open a session. It calls upon an NHManager class to get the session factory. That class implements the singleton pattern.

My business object base class does all the dirty work for nhibernate, so my objects don't really have to implement any CRUD methods. (only 2 lines of code required).

Basically I am getting a "could not load object" exception during a simple Load operation. This has worked for about a month and I just saw this error today. If I refresh my web browser twice (yes, exactly twice) then the problem goes away.

So I set a breakpoint in the NHManager class to see when exactly the session factory was being created. Turns out that the error happens only if the factory was created during that web request, and only for that business object. So far my other objects are fine.

I have double checked the mapping files and don't see anything out of order there.

I'm not sure where to turn now, because there seems to be only a few of us out there that are actively using NHibernate with ASP.NET.. The forums seem dead, but I guess I could try there.

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by yal at 5/26/2005 10:43 AM
Gravatar
Good idea when you run an ASP.NET application but what if you use your data access layer from another application ? You will never close and flush your nhibernate session. Am I right ?

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by Ben Scheirman at 5/26/2005 11:47 AM
Gravatar
Are you referring to me? Yes you are correct, but it wouldn't take much effort to add a section in my NHManager class just like Ben Day has done in his example.

Basically it checks if HttpContext is null, and if so it uses that static reference. This will work just fine for Web+WinForms, but not Web only. So if httpContext is not null, it will load the session from HttpContext.

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by Neil at 7/6/2005 5:38 AM
Gravatar
Hiya,
Cool blog and thanks for the sample code :)

I'm evaluating NHibernate for our projects now, legacy dbs etc. This is perfect!

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by siddik at 7/11/2005 6:42 AM
Gravatar
I need total documentation for simple application using NHibernate and <Net

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by Peter Bromberg at 10/9/2005 9:59 AM
Gravatar
Thanks for the info and sample code. I'm at the "There's only 24 hours in a day, and is it worth my while to study this" phase, and every little bit helps.

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by cil65 at 10/11/2005 2:11 PM
Gravatar
Can you move the nhibernate config out of the UI

# CheckObjectBeforeSave

Left by Hongze at 10/25/2005 10:59 AM
Gravatar
Very good sample!
I find in your service layer BusinessFacade you use CheckObjectBeforeSave to do certain checking before objects being persistented.

In my recent projects, I use the lifecycle call back of NHibernate to do the same thing with good result. Except poisoning model objects with Hibernate stuff, are there others concerns with my approach?

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by Benjamin Day at 10/26/2005 8:35 AM
Gravatar
Hongze,
I don't think I have any major objections to the Lifecycle route other than "poisoning" the models with data access implementation details.

If you're sure that you're not going to want to swap out NHibernate for something else then that "poisoning" is bearable. People use DataSet all over the place in their code. To a certain extent that's poisoning, too. It says "I'm going the MSFT specific data access route."

When you write apps, you have to make decisions and implementation commitments. It's just part of getting stuff done.

Another downside of the Lifecycle approach is that you (probably) put your business logic in with the domain objects. Maybe it's personal preference but I like to keep business logic in a separate assembly and keep my entities as clean and logic-free as possible.

(Although, I can't quick figure why I believe that. Hmmm...I'm going to have to ponder this one. This feels like the beginning of a blog post.)

-Ben

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by KevinW at 10/26/2005 10:23 AM
Gravatar
Ben,
I am just getting started with NHibernate in ASP.Net, and I am a bit confused about when you are building the session factory. I understand that it is expensive to perform this operation. But it looks like you perform it each time the OpenSession method is called, which by what it looks like, is with each Http request. I may not be seeing the code correctly, but I appreciate any help you can provide to better understand how often the factory is built.
Thanks!
Kevin

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by Benjamin Day at 10/26/2005 12:37 PM
Gravatar
KevinW,

I think you might be getting confused with the ASP.NET mode vs. the Windows Mode. That's what's happening with the checks for null on HttpContext.Current.

If the http context is null, that means that we're not running inside of ASP.NET and the module will use static member variables.

If http context is not null, then the reference to the SessionFactory is stored in the HttpContext.Application collection.

Read through the code again and look for http context stuff. It's definitely only creating the sessionfactory once per instance of the NHibernateHttpModule and not on every request.

(disclaimer: unless i posted a bad version of the source code or i'm otherwise totally wrong. haha)

-Ben

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by KevinW at 10/26/2005 7:42 PM
Gravatar
Thanks Ben,

I am still a little confused. This is the code I have downloaded...

public class BaseDataAccess
{

protected ISession m_session;

public BaseDataAccess()
{
m_session=NHibernateHttpModule.CurrentSession;
}

public static ISession OpenSession()
{
Configuration config;
ISessionFactory factory;
ISession session;
config = new Configuration();

if (config==null)
{
throw new InvalidOperationException("NHibernate configuration is null.");
}

config.AddAssembly("Com.Benday.BugTracker.Business");
factory = config.BuildSessionFactory();

if (factory==null)
{
throw new InvalidOperationException("Call to Configuration.BuildSessionFactory() returned null.");
}

session = factory.OpenSession();

if (session==null)
{
throw new InvalidOperationException("Call to factory.OpenSession() returned null.");
}

return session;
}

....

}

Then in the HTTPModule, you have this code...

...

// running inside of an HttpContext (web mode)
// the nhibernate session is a singleton to the http request
HttpContext currentContext = HttpContext.Current;
ISession session = currentContext.Items[KEY] as ISession;
if (session == null)
{
session = BaseDataAccess.OpenSession();
currentContext.Items[KEY] = session;
}
return session;

...

It looks like you are storing ISession in the Context.Items collection, but not the ISessionFactory. Is this the desired approach?

Thanks for your help and explanations! (Sorry for the long post.)

Kevin

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by Benjamin Day at 10/26/2005 8:10 PM
Gravatar
Wow. Big thanks to Kevin on that catch in the sample app. That was a really really old version that definitely had the error he was talking about.

I've posted the current version and fixed that problem.

-Ben

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by KevinW at 10/27/2005 12:00 PM
Gravatar
Thanks for posting the updated sample! Now it is very clear and makes complete sense.
--Kevin

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by Ramadan at 11/9/2005 9:00 PM
Gravatar
The HttpModule route is very problematic. For one, you are instroducing web specific api in your data acess layer. The other solution that was mentioned is to have a static session object. Some concerns with regards to threading was mentioned. If you were to put a lock around the session variable when you are going to use it, that should deal with the threading issue. Another possibility that is coming to mind is Windows Workflow foundation and passing the a ref of the session down to the Activies that you wish to call.

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by Benjamin Day at 11/9/2005 9:13 PM
Gravatar
In response to "Ramadan":

-Putting the web specific code into the HttpModule is a little less than awesome but it allows you to use the same code in a web environment or a Windows environment. It seems like a reasonable compromise.

-Wouldn't making the nhibernate session object static and then wrapping it in lock()'s cause your web application to essentially be single threaded and therefore destroy all hope of a scaleable web app? Plus, you'd probably still have insane weirdness because all current users on the app would be sharing the same session. Technically, it wouldn't be a threading problem anymore...it would just mean that every user could step on every other user's persistent objects.

-I like the sound of the Workflow route but don't know enough about it to say if it'll work. How close is Workflow to production?


-Ben

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by Ramadan at 11/9/2005 9:26 PM
Gravatar
Windows Workflow is in bet 1.2. beta 2 is scheduled for December with the final realeas in june. Beta 1.2 is very functional at this point in time. I am using windows workflow extensively in our current application. The idea here is that you would have activities managing your fetch and updates to the database. In the process of doing this, activities will rely on the state of each other. Hence, a ref to the session object could be shared amongst activities and even amongst workflows.

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by Simon at 3/3/2006 11:04 AM
Gravatar
Great example. Had to change the Save method so it does a refresh after the commit, otherwise any child objects created by FKs seem to be null...or am I missing a more fundamental point?

protected virtual void Save(object item, bool pointlessParameter)
{
ITransaction tx = null;

try
{
tx = m_session.BeginTransaction();

m_session.SaveOrUpdate(item);
tx.Commit();
m_session.Refresh(item);

}
catch (Exception ex)
{
if (tx != null) tx.Rollback();

throw ex;
}
}

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by Benjamin Day at 3/3/2006 11:09 AM
Gravatar
Hey Simon,

Is that refresh() call required with my mapping file or with one that you wrote? If you need to do a refresh, there's probably some kind of mapping file wierdness going on.

-Ben

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by Simon at 3/5/2006 2:27 PM
Gravatar
In my mapping file I added the FK ID field to make it easier to do add/edits, but I guess that has caused this problem. To be honest, I just assumed it was an oversight that in your mapping file you missed off the ID columns but on reflection I now see why!

I'm using an ObjectDataSource with a DetailsView in ASP.NET 2 and I needed to have the ID column for binding to the selectedvalue of a DropDownList.

<asp:DropDownList ID="lstEventCategoryInsert" CssClass="selectgrey" SelectedValue='<%# Bind("EventCategoryID") %>' DataSourceID="EventCategoryDataSource"
DataValueField="ID" DataTextField="Name" runat="server">
</asp:DropDownList>

I can post more of the code if you're interested? FYI Here is my mapping file.

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
<class name="Business.Event, Business" table="Event">
<id name="Id" type="Int32" unsaved-value="0">
<column name="EventID" sql-type="int" not-null="true" unique="true" index="PK_Event"/>
<generator class="native" />
</id>
<property name="EventCategoryID" type="Int32" column="EventCategoryID" not-null="true"/>
<property name="Name" type="String" column="Name" not-null="true"/>
<many-to-one name="EventCategory" class="Business.EventCategory, Business" insert="false" update="false" cascade="all">
<column name="EventCategoryID" sql-type="int" not-null="true"/>
</many-to-one>
</class>
</hibernate-mapping>

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by Dark Night Coder at 5/11/2006 4:48 AM
Gravatar
Hi,
I am facing some other problem.
I want to design such a way that DAL completely abstracted from Presentation layer.

A Business Logic Layer will handle all tasks including Transaction Handling. Can anybody suggest way to handle this ?

BLL will call multiple DAO objects all DAO calls will be under same transaction.
Any thoughts ?

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by Benjamin Day at 5/11/2006 8:16 AM
Gravatar
"Dark Night", I think that the best way to think of this in NHibernate is with two design patterns: Domain Model and Service Layer. Domain Model will be your persistent objects (aka objects managed by NHibernate) and your Service Layer classes will handle all the transaction management stuff.

The UI will talk to the Service Layer to save/load/delete your Domain Model objects. The transaction logic should be completely hidable from your UI.

Hope this helps.

-Ben

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by Dark Night Coder at 5/12/2006 4:19 AM
Gravatar
Thanks Ben,
I am looking at both patterns.

I already made a design plan. I will be great full to you tell whether this is right way.

Conceptual code in C# as follows

In Business Layer functions will be like this

public void BusinessLayerFunction() {
ISession session = NHibernateUtil.GetSession();
ITransaction trans = session.GetTransaction();

AbcDAO abc = new AbcDAO(session , trans);
abc.doThis();
abc.doThat();
XyzDAO xyz = new XyzDAO(session , trans);
xyz.doThat();
xyz.doThis();
NHibernateUtil.Commit(session , trans);
} catch {
NHibernateUtil.RollBack(session , trans);
} finally {
NHibernateUtil.Close(session);
}
Assuming NHibernateUtil is a Lazy Singleton class which provides NHibernate sessions. DAO is using internally NHibernate for persistence. Whether this design still can be improved ?
Any suggestions ?

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by Benjamin Day at 5/12/2006 7:00 AM
Gravatar
Dark Night,
You're moving in the right direction.

It might be easier for you to download one of my sample NHibernate apps from http://www.benday.com/nhibernate and take a look at that.

-Ben

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by Eugene at 5/15/2006 10:43 AM
Gravatar
Hello,

I've been looking and researching for the best approach on how to manage NHibenate session in multi-tier environment. Our team has been successfully manage and implement Hibernate session in multi-tier J2EE framework. Since NHibernate is a clone of Hibernate, we thought it would be easy to apply and implement it in .NET framework but unfortunately most of the samples were not multi-tier compliant.

My idea in multi-tier is that only DAO layer could be the class that connect to database through NHinernate, a UI knows nothing about NHibernate except it calls only the bean or biz layer, and Biz layer manage transaction(COM+) when calling multiple DAO method.

If we could find the best approach on how to manage NHibernate session, I think this could make our life easier. imagine you can create, upate, delete, list a record with minimal coding with OO pattern.

anyway, let's contribute and squeeze NHibernare potentials


regards,
Eugene

# Putting NHibernate session outside ASP.NET

Left by Eugene at 5/25/2006 11:00 PM
Gravatar
Hi Benjamin.

I just want to know if it is possible to put away NHibernate session outside ASP.NET context?Like putting it in in DAO context or at least in BIZ.

Actually we had a project in Java that implement Hibernate and manage the session outside the web appplication. we putted it in a context of EJB(equivalent is COM+ in MS), So our web application knows nothing about the Hibernate session.It resides on DAO level.

So again, is it possible to implement it that way? Or the session can't operate without being
store in HTTP Context in ASP.NEt?

Thanks hope you could answeremy queries.

Regards,
Eugene

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by Benjamin Day at 5/26/2006 7:11 AM
Gravatar
Eugene,

If you look at the implementation of my HttpModule, you'll see that it automatically detects whether it's running in a web app (HttpContext.Current != null) or not (HttpContext.Current == null). If it is running in a web app, it puts the ISession into the HttpRequest's context not the ASPX Session. But if it is running not as a web app, it uses private static member variables to store references to the NHibernate ISession.

It's a little ugly but I wanted a way to make my NHibernate libraries work from the web or from windows forms without having to change anything.

It should be possible to put the ISession pretty much wherever you want because it is Serializable. If you serialize it, you probably have to do is call ISession.Disconnect() before it gets serialized and call ISession.Reconnect() when it gets deserialized.

Does that answer your question?

-Ben

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by MIKE at 6/13/2006 7:17 PM
Gravatar
Hi Ben, Thanks for all your help here. I have a couple of questions.Am I wrong in thinking that if I implement second-level caching on an object and that object is loaded during an HTTP request thru your module, any changes made to that object will be persisted automatically without SaveOrUpdate being called? Say that you want to hold off on edits until the user submits them and in the meantime have the objects in a second-level cache. My object's seem to persist without me formally SaveOrUpdate[ing] (I assume the call to Flush does this?).

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by Jupiter Moon at 6/26/2006 3:18 AM
Gravatar
"Then there's the option of putting the NHibernate session into the ASP.NET Session. That's stinky because it could be open for a really long time and there isn't really any bulletproof way to kill the NHibernate session if the ASP.NET Session gets abandoned or otherwise shut down. "

Erm; Session_OnEnd() per chance?

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by Benjamin Day at 6/26/2006 3:42 AM
Gravatar
Jupiter Moon,

Erm....Session_OnEnd is is not guaranteed to run. Especially if IIS or the ASPX process crashes.

-Ben

# NHibernate session manager

Left by Filimono at 7/6/2006 2:32 PM
Gravatar
I'm holding ISessionFactory in Application and ISession in Context (or create it and close). As far as i know buildfactory is a codegeneration stuff - imho it is not good idea to run it each session...

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by ZipTX at 8/8/2006 2:46 PM
Gravatar
Hey Ben,

Thanks so much for your examples. They got me off the ground and running with nhibernate. I've been working with it for a few weeks now and just went to post my app onto production servers. I am using integrated windows security for my web application and it appears that the security context is a bit different when your app is running on IIS6 accessing a remote SQL server using "Integrated Security=SSPI;"

Your above comment on 5/26 says that nhibernate should be using the HTTP Security context, but it actually uses the Application Pool security context instead of the http user context. The app works fine and in the correct security context when using the Visual Studio Web Server (since it uses the logged on credentials).

Since I am fairly new to nhibernate, I am not sure what to intelligently post for help. All I can think of is when NHibernateHttpModule falls into creating the session in the HttpContext, I could force feed the new session the http security context. But atlas I can't find any examples for doing that.

Any ideas would be GREATLY appreciated.

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by Steinar at 9/20/2006 3:17 PM
Gravatar
Hi Ben!

I haven't had a look on your sample app yet, but I have worked with Hibernate for 2 years and just recently set up a project with NHibernate.

I would say everything is running pretty well, automatic hbmxml generation, database creation and insertion, what a relief.

But I haven't found a good solution for managing the ISession. Currently I'm closing it whenever a DAL broker has finished a user request, delivered it back to a manager which exposes the data object's interface elsewhere (very loose coupling...).

But as you probably know, closing the session after the object has been loaded breaks LazyLoading. Useing a private static member variable to store a reference to the NHibernate ISession, like you do, is no option or solution. Do you have any other possible clean solutions for managing sessions transparently without reproducing code?

Is it possible to intercpet any method that is "annotated" as lazy, provide a session for the scope of the method and post intercept the method-call to close the session? Something like this would be wonderful, with the session-management only defined once...

Thanks, and keep up the good work!
P.S Could you please remove those annoying links above...

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by Damon Carr at 10/5/2006 6:27 AM
Gravatar
All,

One key problem with this approach is it makes it difficult to get your NHibernate classes into a testing framework (or I should say more difficult). In addition I believe it is critical (and kind of the entire point) to abstract the ORM from the UI layer as others here have pointed out.

In other words, your UI Assembly (ASP.NET for example) shouldn't have any references to NHibernate (the NHibernate collections are OK as they are just containers but I would love to hear other's comments).

The entire point of the mapping files is to describe how you would like these things to behave. The mapping files are so expressive I have found you can describe exactly what you need done in an atomic transaction without the need for any Sessions being kept around in your ASP.NET Context. Due to the short life-span of a page, I have found it better to make multiple calls which each get a new connection, do the work, and commit, rather then keep a connection around.

For example: In a web app, lazy-loading is often not possible because the Session will go away (as this solution in this post attempts to fix) at the large cost (in my opinion) of tight coupling and violating one rule of scalability: Acquire resources at the last possible moment and release them as soon as you can (as well as assuming we have a connection pool for the RDMS).

What if we want to change persistence techniques? Yes we would need to deal with the NHibernate collections but that is a much smaller issue and one I can live with. Also if we are still in 1.1 we have to deal with the NHibernate nullable types which is a pain, but again, if this is all in a separate assembly, not as much work.

Here is some sample code for your consideration which does not tie the UI to any ORM. This uses PONOs (plain old .NET objects) in the same way Hibernate likes POJOs:

NOTE: This code is held in the 'Business Services' assembly which is references by our ASP.NET UI. There is no reference to NHibernate in any UI Assembly.


The problem domain is simple for this illustration:

You have a class which defines an 'MemberGroup' which is usually an office in a city (say the New York office). It's parent is 'Member' which is a customer, but I will just focus on OfficeGroup down to make this shorter.

An Member group can define zero, one or more IP Addresses which can be used for 'IP Pass-through' in our system. What this means is that we sniff the IP Address of the user and if it matches an active customer from an office, we ignore the login and they gain access to our site.

Here are the mapping files:

OfficeGroup:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
<class name="BusinessServices.MemberGroup,BusinessServices" table="MemberGroup">

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

<property column="MemberID" type="Int32" name="Memberid" not-null="true" />
<property column="GroupName" type="String" name="GroupName" not-null="true" length="255" />
<property column="EnableIP" type="Byte" name="Enableip" not-null="true" />

<set name="IPAddresses" lazy="false" cascade="all-delete-orphan" inverse="true">
<key column="MemberGroupID"/>
<one-to-many class="BusinessServices.IpLookup,BusinessServices"/>
</set>
</class>
</hibernate-mapping>

And for the IPLookup (each row is an IPAddress or range tied to a MemberGroup via a bidirectional one to many):

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
<class name="BusinessServices.IpLookup,BusinessServices" table="IPLookup">

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

<property column="IPaddress" type="String" name="Ipaddress" not-null="true" length="50" />

<many-to-one name="MemberGroupParent" column="MemberGroupID" not-null="true"/>

</class>
</hibernate-mapping>


Before I show the code for these PONOs, here is code that retrieves a MemberGroup:

MemberGroup oMG;

int KeyVal = x; // Get X however...

oMG = (MemberGroup)DomainFactory.GetDomainClass("BusinessServices.MemberGroup", KeyVal);

oMG.GroupName = txtLocationName.Text;
....
//etc..
oMG.Update();

"BusinessServices.MemberGroup" obviously refers to the type. Normally I would abstract this further in a custom config section so I could refer to this simply as INSTANCE_MEMBER_GROUP and a lookup would find the type string. But you get the idea.

Here is the DomainFactory static method (used for all NHibernate classes):

public static DomainParent GetDomainClass(String TypeName, Int32 InstanceIdentifier)
{

object oResult = null;

// Get a Type - Throw an error if not found
// Do this before opening a session

Type targetType = Type.GetType(TypeName, true);

ISession oSession = ORMServices.GetConnection();

// NOTE: Load throws an exception if not found
// Get returns null

try
{
oResult = oSession.Load(targetType, InstanceIdentifier);
}
catch (Exception ex)
{
// Log Exception
Debug.WriteLine(ex.Message);
}
finally
{
if (oSession.IsConnected)
oSession.Close();
}
return (DomainParent) oResult;
}

And here is the helper method for getting a Session:

public static ISession GetConnection()
{

// NOTE: This is the web singleton.
// We would use another method
// or add code for non-web

HttpApplicationState oApplication = HttpContext.Current.Application;

ISessionFactory FactoryCache;

if (oApplication["ORMFactory"] == null)
{
Configuration cfg = new Configuration();

// NOTE: Assembly name should be in config
cfg.AddAssembly("BusinessServices");

// Do this once only - EXPENSIVE and Thread-Safe
ISessionFactory factory = cfg.BuildSessionFactory();

oApplication["ORMFactory"] = factory;
}


FactoryCache = (ISessionFactory) oApplication["ORMFactory"];

return FactoryCache.OpenSession();

}

And the key to this are the shared methods in the abstract base class. Here we are sharing implementation, however it is likely a good idea to perform an ‘extract interface’ on this as well.

Since every PONO inherits from this base, it automatically can perform create, update and delete. In fact I should move the static ‘Reader’ into this class come to think of it… Anywhere here is the code:

public abstract class DomainParent : IDisposable

Methods:

public virtual void Save()
{
ISession oSession = GetTransaction(out oTrans);
oSession.Save(this);
CompleteAtomicTask(oSession);
}

public virtual void Update()
{
ISession oSession = GetTransaction(out oTrans);
oSession.Update(this);
CompleteAtomicTask(oSession);
}

Etc..

Here are the helper methods:


private ISession GetTransaction(out ITransaction oTransaction)
{
ISession oSession = ORMServices.GetConnection();
oTransaction = oSession.BeginTransaction();
return oSession;
}



private void CompleteAtomicTask(ISession oSession)
{
if (oTrans != null)
{
try
{
oTrans.Commit();
}
catch (Exception ex)
{
oTrans.Rollback();

// NOTE: Sample code..
// Publish Exception using whatever technique you use

Debug.WriteLine(ex.Message);
if (ex.InnerException != null)
Debug.WriteLine(ex.InnerException.Message);
}
finally
{
oTrans = null;
}
}

if (oSession != null && oSession.IsConnected)
oSession.Close();

}

Now for a PONO like MemberGroup all I have to say is:

[Serializable]
public sealed class MemberGroup : DomainParent

As DomainParent defines the CRUD elements, I leave it to the mapping files to determine what to do (say a cascading delete). I never put these mapping files into the UI, always into a separate assembly.

Anyway, there is a lot more to this, including the use of HQL, Query by Criteria, Query by Example, Optimization, Transaction Isolation, etc. If your interested drop me an email. However my main point in this post was to say:

1) It is key that your NHibernate classes be testable (see Michael Feathers book ‘Working Effectively with Legacy Code’ for great material – His ideas work for all code in my opinion
2) There is no need to create a dependency with your UI to NHibernate

Kind Regards,
Damon Carr, CTO
agilefactor


# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by Damon Carr at 10/6/2006 6:52 AM
Gravatar
Please disregard the CODE in the previous post. It is incorrect (a prior version). The latest version is based on the much improved code sample here:

http://www.codeproject.com/aspnet/NHibernateBestPractices.asp

DO NOT use any HttpCopntext storage containers as this will limit your Unit Testing. Instead use:

System.Runtime.Remoting.Messaging.CallContext

Thanks,
Damon Carr

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by Ratko at 9/23/2007 1:41 PM
Gravatar
Maybe you want to check this article (especially if you claim that ystem.Runtime.Remoting.Messaging.CallContext is solution):
http://piers7.blogspot.com/2005/11/threadstatic-callcontext-and_02.html

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by Mark at 10/1/2007 11:56 PM
Gravatar
One potential problem with putting the nhibernate session in HttpModule is when using AJAX - this will cause page headers to be modified and probably cause AJAX parsing exceptions.

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by Edvard Pitka at 10/15/2007 9:21 AM
Gravatar
How about this?
"Instead of solving this problem yourself, you can leverage a new feature of
NHibernate 1.2. It is exposed by the method ISessionFactory.GetCurrentSession().
This method returns the session instance associated with current persistence context,
similar to the ASP.NET notion of a HTTP request context. Any components called in
the same context will share the same session.
When using this feature, the specific context of your application is abstracted. So
your persistence layer will work whether the context is defined by a Web of Windows
context.
The first step to enable this feature is to set the context. This is done using the
configuration property current_session_context_class. For example:
<property name="current_session_context_class">
web
</property>
This example sets the context to web, which is the short name of an implementation
included in NHibernate that uses HttpContext to track the current session. It is
therefore appropriate for ASP.NET applications."

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by ujjwal at 11/6/2007 1:51 AM
Gravatar
hi,
i wanna to handle multiple operations and
in session and trascation how to do it with mulitple session.

regards,
Ujjwal

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by ujjwal at 11/6/2007 2:25 AM
Gravatar
please ignore previous mess.i want to handle multiple operation and in one session,transaction in vb.net using nhibernate.how to do that,
regards,
Ujjwal

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by Daniele at 2/2/2008 6:24 AM
Gravatar
Read the blog and analyzed code: it's exactly as managing the Begin_Request and End_Request in small ASP.NET applications. Nice choice!

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by Paul at 3/18/2008 5:22 PM
Gravatar
@ Edward, I think that is more elegant than using HTTPModules..and as it is built into the dll is the recommended?

# Core .NET

Left by Confluence: Microsoft space at 6/19/2008 10:57 AM
Gravatar
Faglig ansvarsomr�de I faggruppa Core .NET skal vi som m�l � bli utrolig dyktige, effektive og framtidsrettede systemutviklere og l�sningsarkitekter....

# re: NHibernate, Part 3 of xxx: NHibernate Session Management

Left by santhiya at 8/22/2008 5:49 AM
Gravatar

please tell me how to perform the CRUD operation for retrieve of records..

Your comment:



 (will not be displayed)


 
 
 
Please add 1 and 3 and type the answer here:
 

Live Comment Preview: