使用 Repositories/Transactions 时如何管理 NHibernate 会话
How to manage NHibernate sessions when using Repositories/Transactions
我现在陷入了 NHibernate 的困境,我正在努力找出如何最好地正确设计我的存储库,同时正确管理会话的生命周期。
从我看到的示例来看,将 ISession 注入每个存储库似乎是常见的做法,如下所示:
public class SomeRepository : IRepository
{
private readonly ISession _session;
public SomeRepository(ISession session)
{
_session = session;
}
public IList<T> LoadSomeData()
{
return _session.Query<T>().Where(...).ToList();
}
}
这很好,但我可以看到一些会出现问题的情况:
1) 在应用程序的生命周期内可能没有 1 个会话。
2) 当访问 NHibernate 时,我们应该始终将我们的调用包装在事务中——如果事务出错,那么我们必须回滚事务并关闭会话。
在这两种情况下,存储库都将失效,因为它引用了一个已关闭的会话。
我的特定应用程序是一个很长的 运行 进程,它只会偶尔调用 NHibernate,因此我希望会话的周转率很高,而不是在应用程序的整个生命周期中保持 1 个会话打开。
因此我想知道处理这种特殊情况的既定模式是什么?我看到了几个潜在的解决方案,但很难看出哪个是最佳实践:
1) 每次进程需要做一些数据库工作时重建存储库(并创建一个新会话)。
2) 使用 SessionFactory 注入存储库。 Repository 然后公开此 SessionFactory。每个存储库的消费者然后在开始事务的同时打开一个新会话。
3) 创建一个 UnitOfWork class,它被注入到存储库中并负责管理会话生命周期和事务。每次调用 Repository 时,都会调用 UnitOfWork,这会创建一个全新的 Session 并在 Transaction 中执行调用。因此,存储库不知道 Sessions/Transactions.
对我来说,3) 似乎是最好的解决方案,我在网上看到了几个这样的例子,但在所有的例子中,他们只在 UnitOfWork 中创建 1 个会话,如果事务被回滚。
此外,3) 的一个限制是 UnitOfWork 绑定到特定的存储库,因此您不能拥有调用不同存储库的事务。
希望这是有道理的,并希望得到任何指导。
谢谢
其实NHibernate中的Session可以作为UnitOfWork。但是如果你想使用这个模式,这里是实现:http://nhibernate.info/doc/patternsandpractices/nhibernate-and-the-unit-of-work-pattern.html.
但是,您列表中的最佳解决方案是 1。因此,每次需要使用 DB 进行作业时,您都需要创建会话和存储库。
使用 UnitOfWork 看起来像:
using(var uow = new UnitOfWork())
{
var rep1 = new SomeRepository1(uow);
rep1.DoSomeJob();
var rep2 = new SomeRepository2(uow);
rep2.DoSomeOtherJob();
}
使用本机 ISession:
using(var session = SessionFactory.OpenSession())
using(var tr = session.BeginTransaction())
{
var rep1 = new SomeRepository1(session);
rep1.DoSomeJob();
var rep2 = new SomeRepository2(session);
rep2.DoSomeOtherJob();
tr.Commit();
}
您还可以使用 DI/IoC 容器的强大功能来管理会话生命周期。
如果你对最后一个选项感兴趣,我可以给你举个例子。
我现在陷入了 NHibernate 的困境,我正在努力找出如何最好地正确设计我的存储库,同时正确管理会话的生命周期。
从我看到的示例来看,将 ISession 注入每个存储库似乎是常见的做法,如下所示:
public class SomeRepository : IRepository
{
private readonly ISession _session;
public SomeRepository(ISession session)
{
_session = session;
}
public IList<T> LoadSomeData()
{
return _session.Query<T>().Where(...).ToList();
}
}
这很好,但我可以看到一些会出现问题的情况:
1) 在应用程序的生命周期内可能没有 1 个会话。
2) 当访问 NHibernate 时,我们应该始终将我们的调用包装在事务中——如果事务出错,那么我们必须回滚事务并关闭会话。
在这两种情况下,存储库都将失效,因为它引用了一个已关闭的会话。
我的特定应用程序是一个很长的 运行 进程,它只会偶尔调用 NHibernate,因此我希望会话的周转率很高,而不是在应用程序的整个生命周期中保持 1 个会话打开。
因此我想知道处理这种特殊情况的既定模式是什么?我看到了几个潜在的解决方案,但很难看出哪个是最佳实践:
1) 每次进程需要做一些数据库工作时重建存储库(并创建一个新会话)。
2) 使用 SessionFactory 注入存储库。 Repository 然后公开此 SessionFactory。每个存储库的消费者然后在开始事务的同时打开一个新会话。
3) 创建一个 UnitOfWork class,它被注入到存储库中并负责管理会话生命周期和事务。每次调用 Repository 时,都会调用 UnitOfWork,这会创建一个全新的 Session 并在 Transaction 中执行调用。因此,存储库不知道 Sessions/Transactions.
对我来说,3) 似乎是最好的解决方案,我在网上看到了几个这样的例子,但在所有的例子中,他们只在 UnitOfWork 中创建 1 个会话,如果事务被回滚。
此外,3) 的一个限制是 UnitOfWork 绑定到特定的存储库,因此您不能拥有调用不同存储库的事务。
希望这是有道理的,并希望得到任何指导。
谢谢
其实NHibernate中的Session可以作为UnitOfWork。但是如果你想使用这个模式,这里是实现:http://nhibernate.info/doc/patternsandpractices/nhibernate-and-the-unit-of-work-pattern.html.
但是,您列表中的最佳解决方案是 1。因此,每次需要使用 DB 进行作业时,您都需要创建会话和存储库。
使用 UnitOfWork 看起来像:
using(var uow = new UnitOfWork())
{
var rep1 = new SomeRepository1(uow);
rep1.DoSomeJob();
var rep2 = new SomeRepository2(uow);
rep2.DoSomeOtherJob();
}
使用本机 ISession:
using(var session = SessionFactory.OpenSession())
using(var tr = session.BeginTransaction())
{
var rep1 = new SomeRepository1(session);
rep1.DoSomeJob();
var rep2 = new SomeRepository2(session);
rep2.DoSomeOtherJob();
tr.Commit();
}
您还可以使用 DI/IoC 容器的强大功能来管理会话生命周期。
如果你对最后一个选项感兴趣,我可以给你举个例子。