NHibernate.Helper Project

NHibernate.Helper Project

Overview

http://blogs.intesoft.net/simon/articles/16.aspx

When using NHibernate in an ASP.NET application it is important to manage sessions correctly. Typically, a session-per-request pattern is used with a single session created and used for the lifetime of a request and then discarded. This helper project makes using NHibernate with ASP.NET easier by automating the creation of sessions and ensuring that they are closed after each request. It also provides some convenient methods to make coding simpler and more readable:

Automatically create the database schema:

Db.CreateDatabase();

Load an object from the database

Customer customer = (Customer)Db.Load(typeof(Customer), 123);

Save an object:

Db.Save(Customer);

Delete an object:

Db.Delete(Customer);

Access to the NHibernate Configuration and SessionFactory objects are provided if needed.

Configuration

NHibernate already has a comprehensive and flexible configuration system where settings can be defined in code, in the web.config file or in a separate XML file. Using the separate XML file enables the location of the mapping files to be configured as required. The configuration below defines the NHibernate connection properties and driver classes to use (these could also be defined in the web.config file) and the location of the nhibernate mapping files (in this case the assembly 'MyAssembly' which would contain embedded resources).

<?xml version="1.0" encoding="utf-8" ?> 
<hibernate-configuration  xmlns="urn:nhibernate-configuration-2.0" > 
    <session-factory name="chat"> 
        <!-- properties --> 
        <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property> 
        <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property> 
        <property name="connection.connection_string">Server=localhost;initial catalog=nhibernate;Integrated Security=SSPI</property> 
        <property name="show_sql">false</property> 
        <property name="dialect">NHibernate.Dialect.MsSql2000Dialect</property> 
        <property name="use_outer_join">true</property> 
        <property name="query.substitutions">true 1, false 0, yes 'Y', no 'N'</property> 
        <!-- mapping files --> 
        <mapping assembly="MyAssembly" /> 
    </session-factory> 
</hibernate-configuration>

Rather than simply use the default filename "nhibernate.cfg.xml" I prefer instead to use "nhibernate.config", mainly because using an xml file extension is a security risk as the config file could easily be downloaded whereas access to the .config extension is restricted by ASP.NET automatically. To provide some extra flexibility the name of the file is specified in the <appSetting> section with the key "nhibernate.config":

    <appSettings> 
        <add key="nhibernate.config" value="~/nhibernate.config" /> 
    </appSettings> 

Now, the only other thing that needs to be added to the web.config file is the entry for the HttpModule:

    <httpModules> 
        <add name="NHibernateModule" type="NHibernate.Helper.Module, NHibernate.Helper" /> 
    </httpModules> 

Here is the HttpModule itself. As you can see, it is extremly simple and simply closes the connection at the end of the request.

using System; 
using System.Web; 

namespace NHibernate.Helper 
{ 
    /// <summary> 
    ///        HttpModule to automatically close a session at the end of a request 
    /// </summary> 
    public sealed class Module : IHttpModule 
    { 
        public void Init(HttpApplication context) 
        { 
            context.EndRequest += new EventHandler(EndRequest); 
        } 

        public void Dispose() { } 
         
        public void EndRequest(Object sender, EventArgs e) 
        { 
            Db.CloseSession(); 
        } 
    } 
} 

The Db class contains all the helper methods and manages the creation and lifetime of the sessions (with the HttpModule above).

using System; 
using System.Web; 
using System.Configuration; 

using NHibernate; 
using NHibernate.Cfg; 

namespace NHibernate.Helper 
{ 
    /// <summary> 
    ///        Provides access to a single NHibernate session on a per request basis. 
    /// </summary> 
    /// <remarks> 
    ///        NHibernate requires mapping files to be loaded. These can be stored as 
    ///        embedded resources in the assemblies alongside the classes that they are for or 
    ///        in separate XML files. 
    ///        <br /><br /> 
    ///        As the number of assemblies containing mapping resources may change and 
    ///        these have to be referenced by the NHibernate config before the SessionFactory 
    ///        is created, the configuration is stored in a separate config file to allow 
    ///        new references to be added. This would also enable the use of external mapping 
    ///        files if required. 
    ///        <br /><br /> 
    ///        The name of the NHibernate configuration file is set in the appSettings section 
    ///        with the name "nhibernate.config". If not specified the the default value of 
    ///        ~/nhibernate.config is used. 
    ///        <br /><br /> 
    ///        Note that the default config name is not used because the .xml extension is 
    ///        public and could be downloaded from a website whereas access to .config files is 
    ///        automatically restricted by ASP.NET. 
    /// </remarks> 

    public sealed class Db 
    { 
        /// <summary> 
        /// Key used to identify NHibernate session in context items collection 
        /// </summary> 
        private const string sessionKey = "NHibernate.Db"; 

        /// <summary> 
        /// NHibernate Configuration 
        /// </summary> 
        private static readonly Configuration configuration = new Configuration(); 

        /// <summary> 
        /// NHibernate SessionFactory 
        /// </summary> 
        private static readonly ISessionFactory sessionFactory = configuration.Configure( HttpContext.Current.Request.MapPath(ConfigurationSettings.AppSettings["nhibernate.config"]) ).BuildSessionFactory(); 

        /// <summary> 
        /// NHibernate Session. This is only used for NUnit testing (ie. when HttpContext 
        /// is not available. 
        /// </summary> 
        private static readonly ISession session = sessionFactory.OpenSession(); 

        /// <summary> 
        /// None public constructor. Prevent direct creation of this object.  
        /// </summary> 
        private Db() { } 

        /// <summary> 
        /// See beforefieldinit 
        /// </summary> 
        static Db() { } 

        /// <summary> 
        /// Creates a new NHibernate Session object if one does not already exist. 
        /// When running in the context of a web application the session object is 
        /// stored in HttpContext items and has 'per request' lifetime. For client apps 
        /// and testing with NUnit a normal singleton is used. 
        /// </summary> 
        /// <returns>NHibernate Session object.</returns> 
        [CLSCompliant(false)] 
        public static ISession Session 
        { 
            get  
            {  
                ISession session; 
                if (HttpContext.Current == null) 
                { 
                    session = Db.session; 
                } 
                else 
                { 
                    if (HttpContext.Current.Items.Contains(sessionKey)) 
                    { 
                        session = (ISession)HttpContext.Current.Items[sessionKey]; 
                    } 
                    else 
                    { 
                        session = Db.sessionFactory.OpenSession(); 
                        HttpContext.Current.Items[sessionKey] = session; 
                    } 
                } 
                return session;  
            }                 
        } 

        /// <summary> 
        /// Closes any open NHibernate session if one has been used in this request.<br /> 
        /// This is called from the EndRequest event. 
        /// </summary> 
        [CLSCompliant(false)] 
        public static void CloseSession() 
        { 
            if (HttpContext.Current == null) 
            { 
                Db.session.Close(); 
            } 
            else 
            { 
                if (HttpContext.Current.Items.Contains(sessionKey)) 
                { 
                    ISession session = (ISession)HttpContext.Current.Items[sessionKey]; 
                    session.Close(); 
                    HttpContext.Current.Items.Remove(sessionKey); 
                } 
            } 
             
        } 

        /// <summary> 
        /// Returns the NHibernate Configuration object. 
        /// </summary> 
        /// <returns>NHibernate Configuration object.</returns> 
        [CLSCompliant(false)] 
        public static Configuration Configuration 
        { 
            get { return Db.configuration; } 
        } 

        /// <summary> 
        /// Returns the NHibernate SessionFactory object. 
        /// </summary> 
        /// <returns>NHibernate SessionFactory object.</returns> 
        [CLSCompliant(false)] 
        public static ISessionFactory SessionFactory 
        { 
            get { return Db.sessionFactory; } 
        } 

        /// <summary> 
        /// Loads the specified object. 
        /// </summary> 
        /// <param name="type">Type.</param> 
        /// <param name="id">Id.</param> 
        public static void Load(System.Type type, object id) 
        { 
            Db.Session.Load(type, id); 
        } 

        /// <summary> 
        /// Gets the specified object. 
        /// </summary> 
        /// <param name="type">Type.</param> 
        /// <param name="id">Id.</param> 
        public static object Get(System.Type type, object id) 
        { 
            return Db.Session.Get(type, id); 
        } 

        /// <summary> 
        /// Save object item using NHibernate. 
        /// </summary> 
        /// <param name="item">Object to save</param> 
        public static void Save(object item) 
        { 
            ITransaction transaction = Db.Session.BeginTransaction(); 

            try 
            { 
                Db.Session.Save(item); 
                transaction.Commit(); 
            } 
            catch (Exception ex) 
            { 
                transaction.Rollback(); 
                throw; 
            } 
        } 

        /// <summary> 
        /// Save object item using NHibernate. 
        /// </summary> 
        /// <param name="item">Object to delete</param> 
        public static void Delete(object item) 
        { 
            ITransaction transaction = Db.Session.BeginTransaction(); 

            try 
            { 
                Db.Session.Delete(item); 
                transaction.Commit(); 
            } 
            catch (Exception ex) 
            { 
                transaction.Rollback(); 
                throw; 
            } 
        } 

        /// <summary> 
        /// Creates the specified database. 
        /// </summary> 
        /// <param name="script">Script.</param> 
        /// <param name="export">Export.</param> 
        public static void CreateDatabase() 
        { 
            NHibernate.Tool.hbm2ddl.SchemaExport se = new NHibernate.Tool.hbm2ddl.SchemaExport(Db.Configuration); 
            se.Create(true, true); 
        } 
    } 
} 

NHibernate.Helper Project

Overview

When using NHibernate in an ASP.NET application it is important to manage sessions correctly. Typically, a session-per-request pattern is used with a single session created and used for the lifetime of a request and then discarded. This helper project makes using NHibernate with ASP.NET easier by automating the creation of sessions and ensuring that they are closed after each request. It also provides some convenient methods to make coding simpler and more readable:

Automatically create the database schema:

Db.CreateDatabase();

Load an object from the database

Customer customer = (Customer)Db.Load(typeof(Customer), 123);

Save an object:

Db.Save(Customer);

Delete an object:

Db.Delete(Customer);

Access to the NHibernate Configuration and SessionFactory objects are provided if needed.

Configuration

NHibernate already has a comprehensive and flexible configuration system where settings can be defined in code, in the web.config file or in a separate XML file. Using the separate XML file enables the location of the mapping files to be configured as required. The configuration below defines the NHibernate connection properties and driver classes to use (these could also be defined in the web.config file) and the location of the nhibernate mapping files (in this case the assembly 'MyAssembly' which would contain embedded resources).

<?xml version="1.0" encoding="utf-8" ?> 
<hibernate-configuration  xmlns="urn:nhibernate-configuration-2.0" > 
    <session-factory name="chat"> 
        <!-- properties --> 
        <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property> 
        <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property> 
        <property name="connection.connection_string">Server=localhost;initial catalog=nhibernate;Integrated Security=SSPI</property> 
        <property name="show_sql">false</property> 
        <property name="dialect">NHibernate.Dialect.MsSql2000Dialect</property> 
        <property name="use_outer_join">true</property> 
        <property name="query.substitutions">true 1, false 0, yes 'Y', no 'N'</property> 
        <!-- mapping files --> 
        <mapping assembly="MyAssembly" /> 
    </session-factory> 
</hibernate-configuration>

Rather than simply use the default filename "nhibernate.cfg.xml" I prefer instead to use "nhibernate.config", mainly because using an xml file extension is a security risk as the config file could easily be downloaded whereas access to the .config extension is restricted by ASP.NET automatically. To provide some extra flexibility the name of the file is specified in the <appSetting> section with the key "nhibernate.config":

    <appSettings> 
        <add key="nhibernate.config" value="~/nhibernate.config" /> 
    </appSettings> 

Now, the only other thing that needs to be added to the web.config file is the entry for the HttpModule:

    <httpModules> 
        <add name="NHibernateModule" type="NHibernate.Helper.Module, NHibernate.Helper" /> 
    </httpModules> 

Here is the HttpModule itself. As you can see, it is extremly simple and simply closes the connection at the end of the request.

using System; 
using System.Web; 

namespace NHibernate.Helper 
{ 
    /// <summary> 
    ///        HttpModule to automatically close a session at the end of a request 
    /// </summary> 
    public sealed class Module : IHttpModule 
    { 
        public void Init(HttpApplication context) 
        { 
            context.EndRequest += new EventHandler(EndRequest); 
        } 

        public void Dispose() { } 
         
        public void EndRequest(Object sender, EventArgs e) 
        { 
            Db.CloseSession(); 
        } 
    } 
} 

The Db class contains all the helper methods and manages the creation and lifetime of the sessions (with the HttpModule above).

using System; 
using System.Web; 
using System.Configuration; 

using NHibernate; 
using NHibernate.Cfg; 

namespace NHibernate.Helper 
{ 
    /// <summary> 
    ///        Provides access to a single NHibernate session on a per request basis. 
    /// </summary> 
    /// <remarks> 
    ///        NHibernate requires mapping files to be loaded. These can be stored as 
    ///        embedded resources in the assemblies alongside the classes that they are for or 
    ///        in separate XML files. 
    ///        <br /><br /> 
    ///        As the number of assemblies containing mapping resources may change and 
    ///        these have to be referenced by the NHibernate config before the SessionFactory 
    ///        is created, the configuration is stored in a separate config file to allow 
    ///        new references to be added. This would also enable the use of external mapping 
    ///        files if required. 
    ///        <br /><br /> 
    ///        The name of the NHibernate configuration file is set in the appSettings section 
    ///        with the name "nhibernate.config". If not specified the the default value of 
    ///        ~/nhibernate.config is used. 
    ///        <br /><br /> 
    ///        Note that the default config name is not used because the .xml extension is 
    ///        public and could be downloaded from a website whereas access to .config files is 
    ///        automatically restricted by ASP.NET. 
    /// </remarks> 

    public sealed class Db 
    { 
        /// <summary> 
        /// Key used to identify NHibernate session in context items collection 
        /// </summary> 
        private const string sessionKey = "NHibernate.Db"; 

        /// <summary> 
        /// NHibernate Configuration 
        /// </summary> 
        private static readonly Configuration configuration = new Configuration(); 

        /// <summary> 
        /// NHibernate SessionFactory 
        /// </summary> 
        private static readonly ISessionFactory sessionFactory = configuration.Configure( HttpContext.Current.Request.MapPath(ConfigurationSettings.AppSettings["nhibernate.config"]) ).BuildSessionFactory(); 

        /// <summary> 
        /// NHibernate Session. This is only used for NUnit testing (ie. when HttpContext 
        /// is not available. 
        /// </summary> 
        private static readonly ISession session = sessionFactory.OpenSession(); 

        /// <summary> 
        /// None public constructor. Prevent direct creation of this object.  
        /// </summary> 
        private Db() { } 

        /// <summary> 
        /// See beforefieldinit 
        /// </summary> 
        static Db() { } 

        /// <summary> 
        /// Creates a new NHibernate Session object if one does not already exist. 
        /// When running in the context of a web application the session object is 
        /// stored in HttpContext items and has 'per request' lifetime. For client apps 
        /// and testing with NUnit a normal singleton is used. 
        /// </summary> 
        /// <returns>NHibernate Session object.</returns> 
        [CLSCompliant(false)] 
        public static ISession Session 
        { 
            get  
            {  
                ISession session; 
                if (HttpContext.Current == null) 
                { 
                    session = Db.session; 
                } 
                else 
                { 
                    if (HttpContext.Current.Items.Contains(sessionKey)) 
                    { 
                        session = (ISession)HttpContext.Current.Items[sessionKey]; 
                    } 
                    else 
                    { 
                        session = Db.sessionFactory.OpenSession(); 
                        HttpContext.Current.Items[sessionKey] = session; 
                    } 
                } 
                return session;  
            }                 
        } 

        /// <summary> 
        /// Closes any open NHibernate session if one has been used in this request.<br /> 
        /// This is called from the EndRequest event. 
        /// </summary> 
        [CLSCompliant(false)] 
        public static void CloseSession() 
        { 
            if (HttpContext.Current == null) 
            { 
                Db.session.Close(); 
            } 
            else 
            { 
                if (HttpContext.Current.Items.Contains(sessionKey)) 
                { 
                    ISession session = (ISession)HttpContext.Current.Items[sessionKey]; 
                    session.Close(); 
                    HttpContext.Current.Items.Remove(sessionKey); 
                } 
            } 
             
        } 

        /// <summary> 
        /// Returns the NHibernate Configuration object. 
        /// </summary> 
        /// <returns>NHibernate Configuration object.</returns> 
        [CLSCompliant(false)] 
        public static Configuration Configuration 
        { 
            get { return Db.configuration; } 
        } 

        /// <summary> 
        /// Returns the NHibernate SessionFactory object. 
        /// </summary> 
        /// <returns>NHibernate SessionFactory object.</returns> 
        [CLSCompliant(false)] 
        public static ISessionFactory SessionFactory 
        { 
            get { return Db.sessionFactory; } 
        } 

        /// <summary> 
        /// Loads the specified object. 
        /// </summary> 
        /// <param name="type">Type.</param> 
        /// <param name="id">Id.</param> 
        public static void Load(System.Type type, object id) 
        { 
            Db.Session.Load(type, id); 
        } 

        /// <summary> 
        /// Gets the specified object. 
        /// </summary> 
        /// <param name="type">Type.</param> 
        /// <param name="id">Id.</param> 
        public static object Get(System.Type type, object id) 
        { 
            return Db.Session.Get(type, id); 
        } 

        /// <summary> 
        /// Save object item using NHibernate. 
        /// </summary> 
        /// <param name="item">Object to save</param> 
        public static void Save(object item) 
        { 
            ITransaction transaction = Db.Session.BeginTransaction(); 

            try 
            { 
                Db.Session.Save(item); 
                transaction.Commit(); 
            } 
            catch (Exception ex) 
            { 
                transaction.Rollback(); 
                throw; 
            } 
        } 

        /// <summary> 
        /// Save object item using NHibernate. 
        /// </summary> 
        /// <param name="item">Object to delete</param> 
        public static void Delete(object item) 
        { 
            ITransaction transaction = Db.Session.BeginTransaction(); 

            try 
            { 
                Db.Session.Delete(item); 
                transaction.Commit(); 
            } 
            catch (Exception ex) 
            { 
                transaction.Rollback(); 
                throw; 
            } 
        } 

        /// <summary> 
        /// Creates the specified database. 
        /// </summary> 
        /// <param name="script">Script.</param> 
        /// <param name="export">Export.</param> 
        public static void CreateDatabase() 
        { 
            NHibernate.Tool.hbm2ddl.SchemaExport se = new NHibernate.Tool.hbm2ddl.SchemaExport(Db.Configuration); 
            se.Create(true, true); 
        } 
    } 
} 

你可能感兴趣的:(object,session,assembly,resources,extension,HttpModule)