【发布时间】:2012-08-19 11:00:15
【问题描述】:
我正在处理的项目为整个会话定义了一个 UnitOfWork(这似乎是 MVC + NHibernate 站点的标准做法)
不过,我需要做的是能够遍历一组项目并在他们自己的“本地”事务中逐个处理它们。
类似这样的:
foreach(var item in CollectionOfItems)
{
using (ITransaction transaction = UnitOfWork.CurrentSession.BeginTransaction())
{
//do work on item. rollback on failure,
//but it should not affect the other items
}
}
但这不起作用,因为 BeginTransaction 行正在使用相同的“外部”会话。 如何获得一个独立的“本地”会话来对一小段代码执行事务?我认为会话正在以下代码中注入到工作单元中。不过我不知道具体怎么做:
UnitOfWOrk 类具有以下构造函数
private readonly ISessionFactory _sessionFactory;
private readonly ITransaction _transaction;
public UnitOfWork(ISessionFactory sessionFactory)
{
_sessionFactory = sessionFactory;
CurrentSession = _sessionFactory.OpenSession();
_transaction = CurrentSession.BeginTransaction();
}
通过以下方式注册:
For<IUnitOfWork>().LifecycleIs(new HybridLifecycle())
.Use<UnitOfWork>();
因此,每当控制器返回响应时,会话就会被刷新。这就是我感到困惑的地方。我并不总是希望一切都是全有或全无。
编辑:
这里是 NHibernate 注册过程的所有代码
public NHibernateRegistry()
{
FluentConfiguration fluentConfig = Fluently.Configure()
.Database(
MsSqlConfiguration.MsSql2008.ShowSql().ConnectionString(x => x.FromConnectionStringWithKey("conn")))
.ProxyFactoryFactory(typeof (ProxyFactoryFactory).AssemblyQualifiedName)
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<CustomerMap>());
Configuration configuration = fluentConfig.BuildConfiguration();
ConfigureNhibernateValidator(configuration);
ISessionFactory sessionFactory = fluentConfig.BuildSessionFactory();
For<Configuration>().LifecycleIs(new HybridLifecycle()).Singleton().Use(configuration);
For<ISessionFactory>().LifecycleIs(new HybridLifecycle()).Singleton().Use(sessionFactory);
For<ISession>().LifecycleIs(new HybridLifecycle())
.Use(x => x.GetInstance<ISessionFactory>().OpenSession());
For<IUnitOfWork>().LifecycleIs(new HybridLifecycle())
.Use<UnitOfWork>();
For<ITssPrincipal>().HybridHttpOrThreadLocalScoped().Use(container => BuildUserInstanceFromThreadCurrentPrincipal());
Scan(x =>
{
x.TheCallingAssembly();
x.WithDefaultConventions();
});
}
编辑:DI 问题示例 在下面的示例中,您会看到 RepoA 与 RepoB 一起 DI,并且都获得了由 StructureMap 提供的 UnitOfWork。
public RepoA(IUnitOfWork unitOfWork, ITssPrincipal principal,
IRepoB repoB)
{
}
public RepoB(IUnitOfWork unitOfWork, ITssPrincipal principal)
{
}
即使我在 RepoA 中的函数中创建新会话,repoB 仍将使用原始 UnitOfWork 会话
【问题讨论】:
-
您的会话工厂在您执行 foreach 循环的课程中可用吗?除了使用 UnitOfWork.CurrentSession 之外,您还可以使用工厂在循环中创建一个新会话,然后针对该会话调用 BeginTransaction() 吗?
-
我添加了更多代码来显示主会话的设置方式。有没有办法在我的循环中以某种方式使用 fluentConfig.BuildSessionFactory()?
-
Randy 的回答看起来不错,但要添加到您的最后一条评论中:永远记住会话很便宜,但会话 factories 很昂贵。因此,请始终避免创建新工厂(并且通过使用依赖注入,您永远不必这样做)。
-
我认为 DI 是我现在最大的问题。由于 StructureMap 是通过 UnitOfWork 会话为我的所有 repo 类注入的,因此我无法让它们使用新创建的会话(因为此时它们已经被实例化了)
-
我已经用一个例子更新了我的 OP
标签: c# asp.net-mvc nhibernate transactions unit-of-work