2007-05-09 17:51 #0 av: charlie

Om man önskar bygga en Session för ASP.NET och NHibernate så borde denna lilla källkod räcka:

Till att börja med

Om man använder NHibernate så slås man av hur kraftfullt och transparent det är som verktyg för att skapa objekt som beror av en databas. NHibernate är en så kallad Object Relation Mapping (ORM). Det som den gör bättre än de flesta andra verktyg är att mappningen sker utan att själva koden behöver innehålla kunskap om databasens design, så kallade POCO (Plain Old C# Objects). NHibernate sköter dialektskillnader mellan olika databaser och vet om hur olika databas typers representation för den just specifika databasen.

Object State

Eftersom hela syftet med NHibernate designen är att det inte ska finnas någon kunskap om att objektet är presisterat i en DBMS någonstans så behövs någon form av State som beskriver hur ifall ett objekt

  • Persisted innebär att objektet ligger lagrat i databasen
  • Transient innebär att objektet kan ligga i databasen men innehållet är förändrat i förhållande till database

Ett objekt är har sitt state i förhållande till en viss Session.

Session

En session i NHibernate är en specifik uppkoppling emot databasen, dvs man använder samma uppkoppling för att läsa/updatera/lägga till eller ta bort objekt.

För att läsa upp ett Persited objekt från databasen så kan man typ göra följande

int bollId = 10;
Boll boll  = (Boll)  session.Load(typeof(Boll), bollId); 

Problemet är att ASP.NET kan använda samma Request för samma för flera olika sidor så en implementation som bara börjar en NHibernate Session i början av en sida och stänger den i 

using System;
using System.Text;
using System.Web;
using NHibernate;

/*
 * Author: Charlie Helin 2007 (charlie@ifokus.se)
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistribution of source code must retain the above copyright notice, this
 *  list of conditions and the following disclaimer.
 *
 * 2. Redistribution in binary form must reproduce the above copyright notice,
 *  this list of conditions and the following disclaimer in the documentation
 *  and/or other materials provided with the distribution.
 * 
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
 * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE AUTHOR SHALL NOT BE LIABLE
 * FOR ANY DAMAGES SUFFERED BY LICENSEE S A RESULT OF USING, MODIFYING OR
 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL THE AUTHOR
 * BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT,
 * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED
 * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
 * OR INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
 *
 * You acknowledge that this software is not designed, licensed or intended
 * for use in the design, construction, operation or maintenance of any
 * nuclear facility.
 *
 *  Usage:
 * First add to web.config:
 *         <httpModules>
 *            <add type="Util.HttpHibernateSession, Util" name="HttpHibernateSession"/>
 *
 * Secondly, to get the NHibernate session somwhere in the code:
 *     ISession session = Util.HibernateSession.GetSession();
 *
*/

namespace Util
{
    public static class HibernateSession
    {
        private static ISessionFactory factory;


        //In the CInit we would like to initialize the Session Factory. This done purely by introspection,
        //which would require thís class to be in the same assembly
        //as the rest of ORM classes.
        static HibernateSession()
        {
           factory = new NHibernate.Cfg.Configuration()
               .AddAssembly(typeof(HibernateSession).Assembly)
           //Todo: If needed add extra assembiles here
            .BuildSessionFactory();
        }

        //Name to use as the HttpContext key
        private static const string HTTP_CONTEXT_NAME = "HibernateSessionKey";
   

        /// <summary>
        /// Gets the current session from the HttpContext
        /// </summary>
        /// <returns>The current Session (ISession), null if the session was not present</returns>
        public static ISession GetSession()
        {
                lock (HttpContext.Current.Items)
                {
                    if (HttpContext.Current.Items.Contains(HTTP_CONTEXT_NAME))
                    {
                        ISession session = (ISession)HttpContext.Current.Items[HTTP_CONTEXT_NAME];
                        CheckConnectionState(session);
                        return session;
                    }
                }
                return null;
        }

        /// <summary>
        /// Associates a new session with the HttpContext
        /// </summary>
        /// <returns>The current Session (ISession)</returns>
        public static ISession SetSession()
        {
                lock (HttpContext.Current.Items)
                {
                    if (!HttpContext.Current.Items.Contains(HTTP_CONTEXT_NAME))
                    {
                        //Get session from the Session factory
                        HttpContext.Current.Items.Add(HTTP_CONTEXT_NAME,
                           factory.OpenSession());
                    }
                     
                    return GetSession();
                }
        }
       
        /// <summary>
        /// Check that the connection state of the session is open
        /// </summary>
        /// <param name="session">The session to check</param>
        private static void CheckConnectionState(ISession session)
        {
            if (session.Connection.State == System.Data.ConnectionState.Closed)
            {
                session.Connection.Open();
                if (!session.IsConnected)
                {
                    session.Reconnect(session.Connection);
                }
            }
        }

        /// <summary>
        /// Flush (if dirty) and Close the session.
        /// </summary>
        public static void DisposeSession()
        {
            ISession session = GetSession();
            if (session != null && session.IsOpen)
            {
                if (session.IsDirty())
                {
                    session.Flush();
                 }
                 session.Close();
            }
         }
     }
     
    /// <summary>
    /// HttpHibernateSession that will span all ASP.NET pages in a request.
    /// </summary>
    public sealed class HttpHibernateSession : IHttpModule
    {
        #region IHttpModule Members

        /// <summary>
        /// Always on
        /// </summary>
        /// <returns>true</returns>
        private bool IsEnabled()
        {
            return true;
        }

        public void Dispose()
        {
           
        }

        public void Init(HttpApplication context)
        {
            if (IsEnabled())
            {
                //If enabled set callbacks to the BeginRequest and EndRequest events.
                context.BeginRequest += new EventHandler(context_BeginRequest);
                context.EndRequest += new EventHandler(context_EndRequest);
            }
        }

        /// <summary>
        /// Dispse the HibernateSession
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void context_EndRequest(object sender, EventArgs e)
        {
            context.DisposeSession();
        }

        /// <summary>
        /// Setup the HibernateSession
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void context_BeginRequest(object sender, EventArgs e)
        {
            HibernateSession.SetSession();
        }
        #endregion
    }
}