2011-01-28 3 views
3

ContexteComment et où stocker la session NHibernate dans WinForms par demande

J'ai lu toutes sortes de blogs et de la documentation sur la gestion de la session NHibernate. Mon problème, c'est que j'en ai besoin pour les winforms et les webforms. C'est vrai, j'utilise la même couche de données dans une application winforms (windows .exe) et webforms (asp.net web). J'ai lu un peu sur le modèle unit of work et est un bon choix pour winforms. Stocker la session nhibernate dans HttpRequest.Current.Items semble être un bon moyen d'aller chercher des applications web. Mais qu'en est-il un accord de combo? J'ai des applications Web, des applications Windows et des services WCF qui doivent tous utiliser la même couche de données nhibernate. Revenons donc à ma question ...

Je prévois d'utiliser cette conception: NhibernateBestPractices dans mon application web comme ceci:

private ISession ThreadSession { 
    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); // PROBLEM LINE HERE!!! 
     } 
    } 
} 

Le problème

Le problème que j'ai lorsque vous utilisez cette code dans mon application windows, est avec la ligne

CallContext.SetData(SESSION_KEY, value); 

Si je comprends bien CallContext(), cela gardera la session ouvre toute la durée de vie de mon application Windows car elle stocke la session nhibernate dans le thread principal des applications. Et j'ai entendu toutes sortes de mauvaises choses au sujet de garder une session de nhibernate ouverte trop longtemps et je sais par conception, ce n'est pas moyen de rester ouvert très longtemps. Si toutes mes hypothèses sont correctes, alors la ligne de code ci-dessus est un non, non. Compte tenu de tout cela, je voudrais remplacer la ligne ci-dessus avec quelque chose qui va détruire la session nhibernate plus fréquemment dans une application Windows. Quelque chose de similaire à la durée de vie de HttpRequest. Je ne veux pas laisser le client windows connaître la session nhibernate (ou la transaction) et quand l'ouvrir et la fermer. Je voudrais que cela soit déclenché automagiquement.

La question

Alors, où puis-je stocker la session NHibernate dans une application windows qui me permettra (ie. Autre chose que le client) pour commencer automatiquement et mettre fin à une transaction sur une demande par base de données (c'est-à-dire, chaque fois qu'un client appelle la base de données)?

** Mise à jour **

Voici 2 autres liens sur la façon de mettre en œuvre l'unité de modèle de travail

http://msdn.microsoft.com/en-us/magazine/dd882510.aspx

http://www.codeinsanity.com/2008/09/unit-of-work-pattern.html

Répondre

1

Chacune de vos applications peut fournir un implémentation commune d'une interface comme IUnitOfWorkStorage

public interface IUnitOfWorkStorage 
{ 
    void StoreUnitOfWork(IUnitOfWork uow); 
} 

IUnitOfWork peut être une enveloppe autour de la ISession qui peut ressembler à ceci

public interface IUnitOfWork 
{ 
    void Begin(); 
    void End(); 
} 

Begin pourrait ouvrir la session et démarrer une transaction, alors que End commettrait la transaction et fermer la session.Vous pouvez donc avoir 2 implémentations de IUnitOfWorkStorage, une pour la WebApp et une pour l'application Windows. L'application Web peut utiliser HttpContext.Current ou quelque chose et votre application Windows ne peut fournir qu'un simple magasin d'objets qui est disposé à la fin de votre action, ce qui mettrait fin à UnitOfWork.

+0

Merci pour la brève explication du motif d'unité de travail. J'avais besoin de plus d'infos mais j'ai trouvé quelques liens expliquant cela plus en détail (voir la mise à jour dans mon post). –

1

J'ai fini par utiliser le code suivant. Le seul "fardeau" qu'il a mis sur mon application était les tests unitaires, et je préfère muck ce code avec des informations spécifiques à la session que le code de production. J'ai gardé le même code que mentionné dans ma question, puis ajouté cette classe à mon projet de test unitaire:

namespace MyUnitTests 
{ 
    /// <summary> 
    /// Simulates the IHttpModule class but for windows apps. 
    /// There's no need to call BeginSession() and EndSession() 
    /// if you wrap the object in a "using" statement. 
    /// </summary> 
    public class NhibernateSessionModule : IDisposable 
    { 
     public NhibernateSessionModule() 
     { 
      NHibernateSessionManager.Instance.BeginTransaction(); 
     } 

     public void BeginSession() 
     { 
      NHibernateSessionManager.Instance.BeginTransaction(); 
     } 

     public void EndSession() 
     { 
      NHibernateSessionManager.Instance.CommitTransaction(); 
      NHibernateSessionManager.Instance.CloseSession(); 
     } 

     public void RollBackSession() 
     { 
      NHibernateSessionManager.Instance.RollbackTransaction(); 
     } 

     #region Implementation of IDisposable 

     public void Dispose() 
     { 
      // if an Exception was NOT thrown then commit the transaction 
      if (Marshal.GetExceptionCode() == 0) 
      { 
       NHibernateSessionManager.Instance.CommitTransaction(); 
      } 
      else 
      { 
       NHibernateSessionManager.Instance.RollbackTransaction(); 
      } 
      CloseSession(); 
     } 

     #endregion 
    } 
} 

Et utiliser la classe ci-dessus, vous feriez quelque chose comme ceci:

[Test] 
public void GetByIdTest() 
{ 
    // begins an nhibernate session and transaction 
    using (new NhibernateSessionModule()) 
    { 
     IMyCustomer myCust = MyCustomerDao.GetById(123); 
     Assert.IsNotNull(myCust);   
    } // ends the nhibernate transaction AND the session 
} 

Remarque: Si vous utilisez cette méthode assurez-vous de ne pas envelopper vos sessions dans des instructions "using" lors de l'exécution de requêtes à partir de vos classes Dao comme dans this post. Comme vous gérez vous-même des sessions et les gardez ouvertes plus longtemps qu'une seule session par requête, vous devez vous débarrasser de tous les endroits où vous fermez la session et laisser le NhibernateSessionModule faire cela pour vous (applications Web ou applications Windows).

Questions connexes