3

背景

我已经阅读了有关 nhibernate 会话管理的各种博客和文档。我的问题是,winforms 和 webforms 都需要它。没错,我在 winforms (windows .exe) 和 webforms (asp.net web) 应用程序中都使用了相同的数据层。我已经阅读了一些有关工作单元 模式的信息,并且是 winforms 的不错选择。在 HttpRequest.Current.Items 中存储休眠会话似乎是 Web 应用程序的好方法。但是组合交易呢?我有 Web 应用程序、Windows 应用程序和 WCF 服务,它们都需要使用相同的休眠数据层。所以回到我的问题...

我打算在我的网络应用程序中使用这种设计: NhibernateBestPractices ,如下所示:

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!!!
        }
    }
}

问题

在我的 Windows 应用程序中使用此代码时遇到的问题是行

CallContext.SetData(SESSION_KEY, value);

如果我理解 CallContext() 正确,这将使会话在我的 Windows 应用程序的整个生命周期中保持打开状态,因为它将休眠会话存储为主应用程序线程的一部分。而且我听说过关于保持休眠会话打开时间过长的各种不好的事情,我知道从设计上讲,保持打开时间很长并不意味着。如果我所有的假设都是正确的,那么上面的代码行是不,不。

鉴于这一切,我想用会在 Windows 应用程序中更频繁地破坏休眠会话的东西替换上面的行。类似于 HttpRequest 的生命周期。我不想让 Windows 客户端知道休眠会话(或事务)以及何时打开和关闭它。我希望它自动触发。

问题

那么,我在哪里可以将 nhibernate 会话存储在 Windows 应用程序中,这将允许我(即客户端之外的其他东西)自动开始和结束每个数据库请求的事务(即,每当客户端调用数据库时) )?

**更新**

这里有 2 个关于如何实现工作单元模式的链接

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

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

4

2 回答 2

1

您的每个应用程序都可以提供接口的通用实现,例如 IUnitOfWorkStorage

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

IUnitOfWork 可以是 ISession 的包装器,看起来像这样

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

Begin可能会打开会话并启动事务,同时End会提交事务并关闭会话。因此,您可以有 2 种实现IUnitOfWorkStorage,一种用于 WebApp,一种用于 Windows 应用。Web 应用程序可以使用 HttpContext.Current 或其他东西,而您的 Windows 应用程序可以只提供一个简单的对象存储,该对象存储在您的操作结束时处理,这将结束 UnitOfWork。

于 2011-01-29T15:18:00.413 回答
1

我最终使用了以下代码。它给我的应用程序带来的唯一“负担”是单元测试,我宁愿用生产代码的会话特定信息来处理该代码。我保留了与我的问题中提到的相同的代码,然后将此类添加到我的单元测试项目中:

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
    }
}

要使用上面的类,你会做这样的事情:

[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
}

注意:如果您使用此方法,请确保在执行来自 Dao 类的查询时,不要将会话包装在“使用”语句中,如本文中所示。因为您自己管理会话并使它们保持打开的时间比每个查询一个会话的时间长一点,所以您需要摆脱关闭会话的所有地方并让 NhibernateSessionModule 为您做这件事(Web 应用程序或 Windows 应用程序)。

于 2011-02-02T17:45:50.287 回答