Samedi le 4 février 2012 . 16:18

Gestion des sessions NHibernate

Dimanche, 23 novembre 2008, 16:14
Cet article a été publié dans Développement et a 0 commentaire à ce jour .

La gestion des sessions est un aspect crucial pour tirer avantage de l’utilisation de NHibernate. Le problème vient du fait que la construction du SessionFactory qui gère les transactions et sessions de NHibernate est assez coûteuse. Il existe plusieurs stratégies pour gérer ce problème avec ASP.Net. Dave Byron propose une solution assez simple via un pattern de Unit of Work. Toutefois, cette méthode nécessite également des connaissances des patterns de Depency Injection et de Inversion of Control.

C’est pourquoi celle que je présente ici est exactement celle proposée par Billy McCafferty dans son article NHibernate Best Practices with ASP.Net. La méthode utilise un pattern de Singleton dont l’implantation en C# est présentée sur cette page. Un avantage de cette méthode est qu’elle fonctionnera que vous utilisiez ASP.Net ou bien les WinForms.

using System.Runtime.Remoting.Messaging;
using System.Web;
using NHibernate;
using NHibernate.Cache;
using NHibernate.Cfg;

namespace NHibernateHelper
{
    /// <summary>
    /// Handles creation and management of sessions and transactions.  It is a singleton because
    /// building the initial session factory is very expensive. Inspiration for this class came
    /// from Chapter 8 of Hibernate in Action by Bauer and King.  Although it is a sealed singleton
    /// you can use TypeMock (http://www.typemock.com) for more flexible testing.
    /// </summary>
    public sealed class NHibernateSessionManager
    {
        #region Thread-safe, lazy Singleton

        /// <summary>
        /// This is a thread-safe, lazy singleton.  See http://www.yoda.arachsys.com/csharp/singleton.html
        /// for more details about its implementation.
        /// </summary>
        public static NHibernateSessionManager Instance {
            get {
                return Nested.NHibernateSessionManager;
            }
        }

        /// <summary>
        /// Initializes the NHibernate session factory upon instantiation.
        /// </summary>
        private NHibernateSessionManager() {
            InitSessionFactory();
        }

        /// <summary>
        /// Assists with ensuring thread-safe, lazy singleton
        /// </summary>
        private class Nested
        {
            static Nested() { }
            internal static readonly NHibernateSessionManager NHibernateSessionManager =
                new NHibernateSessionManager();
        }

        #endregion

        private void InitSessionFactory() {
            sessionFactory = new Configuration().Configure().BuildSessionFactory();
        }

        /// <summary>
        /// Allows you to register an interceptor on a new session.  This may not be called if there is already
        /// an open session attached to the HttpContext.  If you have an interceptor to be used, modify
        /// the HttpModule to call this before calling BeginTransaction().
        /// </summary>
        public void RegisterInterceptor(IInterceptor interceptor) {
            ISession session = ContextSession;

                if (session != null && session.IsOpen) {
                throw new CacheException("You cannot register an interceptor once a session has already been opened");
            }

            GetSession(interceptor);
        }

        public ISession GetSession() {
            return GetSession(null);
        }

        /// <summary>
        /// Gets a session with or without an interceptor.  This method is not called directly; instead,
        /// it gets invoked from other public methods.
        /// </summary>
        private ISession GetSession(IInterceptor interceptor) {
            ISession session = ContextSession;

            if (session == null) {
                if (interceptor != null) {
                    session = sessionFactory.OpenSession(interceptor);
                }
                else {
                    session = sessionFactory.OpenSession();
                }

                ContextSession = session;
            }

            return session;
        }

        /// <summary>
        /// Flushes anything left in the session and closes the connection.
        /// </summary>
        public void CloseSession() {
            ISession session = ContextSession;

            if (session != null && session.IsOpen) {
                session.Flush();
                session.Close();
            }

            ContextSession = null;
        }

        public void BeginTransaction() {
            ITransaction transaction = ContextTransaction;

            if (transaction == null) {
                transaction = GetSession().BeginTransaction();
                ContextTransaction = transaction;
            }
        }

        public void CommitTransaction() {
            ITransaction transaction = ContextTransaction;

            try {
                if (HasOpenTransaction()) {
                    transaction.Commit();
                    ContextTransaction = null;
                }
            }
            catch (HibernateException) {
                RollbackTransaction();
                throw;
            }
        }

        public bool HasOpenTransaction() {
            ITransaction transaction = ContextTransaction;

            return transaction != null && !transaction.WasCommitted && !transaction.WasRolledBack;
        }

        public void RollbackTransaction() {
            ITransaction transaction = ContextTransaction;

            try {
                if (HasOpenTransaction()) {
                    transaction.Rollback();
                }

                ContextTransaction = null;
            }
            finally {
                CloseSession();
            }
        }

        /// <summary>
        /// If within a web context, this uses <see cref="HttpContext" /> instead of the WinForms
        /// specific <see cref="CallContext" />.  Discussion concerning this found at
        /// http://forum.springframework.net/showthread.php?t=572.
        /// </summary>
        private ITransaction ContextTransaction {
            get {
                if (IsInWebContext()) {
                    return (ITransaction)HttpContext.Current.Items[TRANSACTION_KEY];
                }
                else {
                    return (ITransaction)CallContext.GetData(TRANSACTION_KEY);
                }
            }
            set {
                if (IsInWebContext()) {
                    HttpContext.Current.Items[TRANSACTION_KEY] = value;
                }
                else {
                    CallContext.SetData(TRANSACTION_KEY, value);
                }
            }
        }

        /// <summary>
        /// If within a web context, this uses <see cref="HttpContext" /> instead of the WinForms
        /// specific <see cref="CallContext" />.  Discussion concerning this found at
        /// http://forum.springframework.net/showthread.php?t=572.
        /// </summary>
        private ISession ContextSession {
            get {
                if (IsInWebContext()) {
                    return (ISession)HttpContext.Current.Items[SESSION_KEY];
                }
                else {
                    return (ISession)CallContext.GetData(SESSION_KEY);
                }
            }
            set {
                if (IsInWebContext()) {
                    HttpContext.Current.Items[SESSION_KEY] = value;
                }
                else {
                    CallContext.SetData(SESSION_KEY, value);
                }
            }
        }

        private bool IsInWebContext() {
            return HttpContext.Current != null;
        }

        private const string TRANSACTION_KEY = "nhibernate.context.transaction.key";
        private const string SESSION_KEY = "nhibernate.context.session.key";
        private ISessionFactory sessionFactory;
    }
}

Un petite note: peu importe la méthode utilisée, si vous êtes dans un contexte Web, il faut généralement s’assurer que la méthode est Thread-Safe.

Une question demeure toutefois, quand doit-on créer les sessions et transactions et quand doit-on les fermer? La documentation suggère de mettre en oeuvre le pattern Open-In-Session-View afin de mettre à profit les possiblités de lazy-loading de NHibernate. Billy McCafferty mentionnait dans son article:

If you want to leverage NHibernate’s lazy-loading (which you most certainly will), then the Open-Session-in-View pattern is the way to go. (”Session” in this context is the NHibernate ISession…not the ASP.NET Session object.) Essentially, this pattern suggests that one NHibernate session be opened per HTTP request.

Encore une fois, l’approche proposée est celle que je présente. Le pattern signifie qu’une session NHibernate doit être ouverte par requête HTTP. En asp.net, le plus simple pour accomplir cette tâche à mon avis est en effet de créer un IHttpModule. On crée la session au début de la requête et on la ferme à la fin. S’il y a des changements à effectués, ils seront engagés avant la fermeture de la session. S’il y a des erreurs, la transaction sera annulée et la session sera quand même fermée. Voici le code du module qui se veut assez simple.

using System;
using System.Web;

namespace NHibernateHelper.Modules
{
    /// <summary>
    /// Implements the Open-Session-In-View pattern using <see cref="NHibernateSessionManager" />.
    /// Assumes that each HTTP request is given a single transaction for the entire page-lifecycle.
    /// Inspiration for this class came from Ed Courtenay at
    /// http://sourceforge.net/forum/message.php?msg_id=2847509.
    /// </summary>
    public class NHibernateSessionModule : IHttpModule
    {
        public void Init(HttpApplication context) {
            context.BeginRequest += new EventHandler(BeginTransaction);
            context.EndRequest += new EventHandler(CommitAndCloseSession);
        }

        /// <summary>
        /// Opens a session within a transaction at the beginning of the HTTP request.
        /// This doesn't actually open a connection to the database until needed.
        /// </summary>
        private void BeginTransaction(object sender, EventArgs e) {
            NHibernateSessionManager.Instance.BeginTransaction();
        }

        /// <summary>
        /// Commits and closes the NHibernate session provided by the supplied <see cref="NHibernateSessionManager"/>.
        /// Assumes a transaction was begun at the beginning of the request; but a transaction or session does
        /// not *have* to be opened for this to operate successfully.
        /// </summary>
        private void CommitAndCloseSession(object sender, EventArgs e) {
            try {
                NHibernateSessionManager.Instance.CommitTransaction();
            }
            finally {
                NHibernateSessionManager.Instance.CloseSession();
            }
        }

        public void Dispose() { }
    }
}

Voilà, il ne vous reste plus qu’à configurer le module http dans votre web.config et vous serez en mesure de gérer vos sessions NHibernate sans trop de problèmes.

Finalement, un simple exemple pour exécuter une requête via notre gestionnaire de session:

...
ISession session = NHibernateSessionManager.Instance.GetSession();
return session.Get<T>(id);
Vous pouvez passer à la fin et laisser une réponse. Les pings ne sont actuellement pas autorisés.

Commenter sur “Gestion des sessions NHibernate”

Laisser un commentaire

viagra costs walmart
cipla canada
Cialis generic alternative
depoxetine
buy dapoxetine online
dsicount viagra
order cialis 20mg
where can I buy cialis 20mg
viagra loest prise
discount cialis 20mg
viagra sale
buy super viagra
viagrasuperforte
cialis no prescription canada
viagra paypal payment canada
viagra soft tabs
sildenafil
Generic Levitra
buy levitra
viagra cheap
levitra bayer
36 hour cialis mg
causes of irectal dysfuction
generic viagra 50mg
generic cialis
cialis black 800mg
montreal online pharmacy
buy generic viagra
canada customs and cialis
calis
generic viagra from india
order viagra from canada
cialis 20mg price
cialis coupons
buy cialis using paypal
cialis 10mg
viagra by mail
walmart pharmacy viagra
pfizer viagra online
viagra price
Vardenafil HCL
ed pro trial pack
buy generic levitra no prescription
china Pharmacy
proscar 5mg
VIAGRA online
cialis 20mg prices
viagra cialis combo
levitra
cialis with dapoxetine
drugstore 1st
cialis 20 mg from united kingdom
cialis black
viagra low cost
cialis for daily use
tadalafil daily use
cialis
generic viagara
buy DAPOXETINE
canada viagra overnight
accutane for sale online
viagra free trial offer
Sildenafil
real viagra paypal
levitra forum
Sildenafil citrate 50mg
buy viagra online ireland
Cheap viagra
cialis professional
20mg cialis
cialis promise program
viagra coupon
viagRA online
cialis sales
VIAGRA FOR DAILY USE
generic levitra overnight delivery
edtrustedmedstore
cialis tablets
Generic Viagra
viagra canada
where can i buy finasteride
viagra trial sample
order viagra
buy viagra
nolvadex
cheap generic viagra pills
discount viagra
HTMLGIANT LEVITRA
generic cialis in canada
buying viagra with next day shipping
mixing cocaine and viagra
dapoxetine
viagra prices walmart
buy strong viagra
original cialis
Viagra on line
genuine viagra australia
generic viargra
cialis online canada
cialis paypal payment
us cialis online pharmacy
ordering cialias
where to buy cialis
100mg Viagra
buy viagra for women germany
cheap generic viagra 100mg
walmart cialis price
whats the least expensive place to buy viagra
Levitra
levitra 10mg buy
Buy viagra online
buy dapoxetine
cheap generic cialis
generic propecia
generic viagia
sildenafil online canada
cialis super active review
cialis viagra cocktail
buy viagra in canada fast
viagra online
generic cialis cipla
buying viagra online in montreal
kamagra for sale
i need cialis
VIAGRA IN USA
cialis super active vs professional
cialis without prescription
cialis viagra levitra canada
is super active cialis a scam
european cialis
tadalifil
sildenafil tablets
next day shipping viagra
10mg cialis
viagra and pregancy
where to buy viagra in calgary
low dose cialis
cheapest generic levitra
liquid viagra to buy
viagra no prescription
cheap sildenafil
Sildenafil citrate 100mg
sildenafil citrate overnight delivery
buy viagra using paypal
generic cialis
viagra no perscription
where to buy viagra in toronto
alternatives to viagra
canada generic viagra
viagra online without prescription
price of tadalafil 20 mg
cialis 36 hour
cheap sildenafil citrate
cialis 20 mg
viagra and dapoxetine
generic viagra
viagra for sale australia
walmartcanadapharmacy
cialis online nz
buy generic propecia
30 day free cialis
Viagra for sale
levitra buy
viagra no prescription
viagra generic
what works as well as viagra
generis cialis
buy propecia
viagra jelly sachet
viagra mail order
buy viagra no prescription
BUYING EGYPT VIAGRA
buy viagra online
vardenafil
viagra in uk
viagra softtabs
cealis generic
viagra patent expiration date
viagra canada free sample
levitra coupons pharmacy
buy viagra canada
buy viagra online
finasteride
sildenafil citrate generic
Lowest prices on Viagra Super Force 100mg/60mg pills
cheaP viagra
100mg viagra
Cialis
viagra usa
status 365 pills
Cheap Viagra
cialis soft tabs canada
sildenafil 100mg
viagra online netherlands
cheapest cialis 20mg
tadalafil soft gelatin capsules
noriskpharmacy
street value for viagra
VIAGRA ONLINE
pfizer viagra price
Nolvadex
chip viagra
Dapoxetine
buy levitra online
generic viagra soft tabs
cialis canada pharmacy
drugstore 365 org order levitra online
canada viagra paypal
centerpill
viagra nz
cialis online
viagra from tijuana
overnight pharma
cialis + dapoxetine
viagra price comparison
cialis men
pills house
cialis generic
Viagra cheap
generic viagra
kamagra tablets
+viagra
propecia
where can i buy generic viagra
Sildenafil Citrate
canadian levitra vs usa levitra
30 day free trial of cialis
viagra suppliers canada
buy proscar
buy cialis no prescription
pillshouse
low cost viagra
cialis overnight
finasteride sale
cialis no prescrition
viagra on line
viagra melbourne
cialis+price
buy viagra usa
best viagra deals from India
canadian cialis online
super viagra uk
brand name viagra canada
viagra for sale
buy viagra without prescription
canadian pharmacies selling viagra
propecia generic finasteride
cialis black reviews
viagra paypal checkout
viagra for women for sale
cheap cialis generic online
can i take cialis with daxpoteine
generic cialas
where can i get viagra across the counter in the uk
cialis online uk
buy cialis
viagra no prescription canada pfizer
viagra online without a prescription
cialis coupon
tadalafil dosage
propecia
viagra alcohol effects
Finasteride purchase
cialis daily
cialis for sale nz
Generic viagra
cheap vigra
free viagra sample pack
cialis south africa
clomid
order cialis 20 online
cilias 20mg
PROSCAR
brand cialis
nolvadex for sale
viagra canada sales
cheapest cialis tadalafil 20 mg
cialis 40 mg
walmartprices for viagra
buy real viagra with a echeck
cheapest viagra
viagra no prescription overnight
what is the ingredients in viagra
cialis no prescription
lilly cialis 20mg
viagra next day delivery usa
viagra online nz
viagraonline\
buy original cialis 10 mg
CIALIS No prescription
viagra single tabs
generic Viagra
cialis 5mg
ordering viagra onl
indo viagral
viagra for sale in ireland
black tab cialis
viagra 100 tablets
buy nolvadex
viagra video
viagra deals
cost of viagra
GENERIC CIALIS WITH DAPOXETINE 80MG
genaric viagra
buy finasteride
tramadol side effects dysfunction
buy cialis 20 mg
1 800 490 0365
cialis no perscription
viagra vs cialis which is better
online overnight viagra
generic ciallis
cialis 200 mg price
compralviagra
propecia cost
how to buy viagra from canada
viragra
viagra uk
Viagra
generic viagra 50 mg
cialis for sale canada
finasteride 1mg generic
viagra no prescrition
Viagra prices
cheap viagra 50 mg
cialis voucher
Generic Viagra
cheap levitra online india
order viagra online
Proscar
generic viagra canada
pharmacy express
viagra without a script
viagra australia no prescription
planet pharma warehouse pvt ltd
cailis online
super active cialis with no prescription
Cialis online
viagra sales
levitra professional 100mg
where to buy viagra
levitra substitute
viagra no prescription
vpxl
overnightpharmacy4u
viagra uk
finasteride 1mg
viagra canada no prescription
Cialis 50mg price
viagra for sell
NEXIUM FOR SALE
cialis overnight shipping
levitra generic
viagra in united states
buy generic cialis
1 mg propecia
cialis for daily use disount
levitra coupon
buy wholesale viagra
pfizer viagra without prescription
viagra quebec
generic cialis 20mg
cialis without prescriptions
buy Dapoxetine
ebay + cialis
viagra levitra which is best
viagra levitra cialis offers
canada pharmacy generic cialis
generic viagra price
viagra express
where to buy Propecia
tadalafil
generic vs brand name viagra
generic levitra for sale
generic levitra
levitra online canadian
Female Cialis
cialis daily
viAGRA ONLINE
sildenafil citrate
viagra prices
viagra for boys
walmart canada pharmacy
cialis to buy
.buy viagra
buy viagra Australia
cialisonline
viagra online, no prescription
cheap viagra online
buy cialis generic
buy viagra online sydney
ggeneric viagra for sale
viagra for sale online
original viagra for sale
100 ml viagra for sale
levitra 100mg uk
order levitra
Sildenafil Citrate
viagra 100mg
supreme suppliers cialis
levitra dosage 40 mg
sildenafil citrate 100mg
purchase propecia
viagra patent date
CHEAP VIAGRa
Finasteride 1mg
Buy Viagra online
cialis onlilne
where to buy genuine viagra online
inderal overnight
online viagra no prescription
cialis vs viagra