【问题标题】:Exposing transactions on Repository. NHibernate在存储库上公开事务。休眠
【发布时间】:2026-01-09 11:00:02
【问题描述】:

所以目前我有这样一个存储库实现:

public class Repository<T> : IRepository<T> where T : AbstractEntity<T>, IAggregateRoot
{
    private ISession session;

    public Repository(ISession session)
    {
        this.session = session;
    }

    public T Get(Guid id)
    {            
        return this.session.Get<T>(id);            
    }
    public IQueryable<T> Get(Expression<Func<T, Boolean>> predicate)
    {
        return this.session.Query<T>().Where(predicate);            
    }
    public IQueryable<T> Get()
    {
        return this.session.Query<T>();            
    }
    public T Load(Guid id)
    {
        return this.session.Load<T>(id);
    }
    public void Add(T entity)
    {            
        using(var transaction = this.session.BeginTransaction())
        {
            this.session.Save(entity);
            transaction.Commit();
        }
    }
    public void Remove(T entity)
    {            
        using(var transaction = this.session.BeginTransaction())
        {
            this.session.Delete(entity);
            transaction.Commit();
        }
    }
    public void Remove(Guid id)
    {            
        using(var transaction = this.session.BeginTransaction())
        {
            this.session.Delete(this.session.Load<T>(id));
            transaction.Commit();
        }
    }
    public void Update(T entity)
    {            
        using(var transaction = this.session.BeginTransaction())
        {
            this.session.Update(entity);
            transaction.Commit();
        }
    }
    public void Update(Guid id)
    {            
        using(var transaction = this.session.BeginTransaction())
        {
            this.session.Update(this.session.Load<T>(id));
            transaction.Commit();
        }
    }
}

然后我像这样使用Ninject 模块。

public class DataAccessModule : Ninject.Modules.NinjectModule
{
    public override void Load()
    {
        this.Bind<ISessionFactory>()
            .ToMethod(c => new Configuration().Configure().BuildSessionFactory())
            .InSingletonScope();

        this.Bind<ISession>()
            .ToMethod(ctx => ctx.Kernel.TryGet<ISessionFactory>().OpenSession())
            .InRequestScope();

        this.Bind(typeof(IRepository<>)).To(typeof(Repository<>));
    }
}

Schema 导出和更新被称为测试:

[TestFixture]
public class SchemaManipulations
{
    [Test]
    [Ignore]
    public void CreateDatabaseSchema()
    {
        new SchemaExport(new Configuration().Configure()).Create(false, true);
    }

    [Test]
    [Ignore]
    public void UpdateDatabaseSchema()
    {
        new SchemaUpdate(new Configuration().Configure()).Execute(false, true);
    }
}

我保持“干净”我的域层:验证逻辑是用FluentValidation 实现的,它不知道NHibernate 没有其他任何东西。

这对我来说似乎很完美......直到我想知道如何实现版本并发。我选择使用optimistic-locking,至于为NH 正确映射它不是问题。我需要知道如何处理事务,在编辑locked 项目时如何通知用户?

于是又出现了一个问题version concurrency control for a long session. NHibernate. ASP.NET MVC,据说不建议在Repository 上公开交易。

问题本身

我已经听说过SharpArchitectureUOW。这够了

但我对我的数据访问策略解决方案提供的问题很感兴趣:这样使用它会遇到哪些错误/故障?

使用Kaleb Pederson NHibernate, transactions and TransactionScope 提出的方法也是一种解决方案吗?

谢谢!

【问题讨论】:

  • IN 除了下面的答案,我想说不要使用 TransactionScope 有几个原因。首先是它是否可以工作取决于您使用的数据库数据提供者。因此,如果您只使用 SQL Server,它可能没问题。此外,如果您马虎并最终获得多个会话/连接,它会自动将事务提升到 DTC,这是您(可能)不想要的。我会看一下每个请求模式的会话。这种模式有多种实现方式,因此我将留给您确定最适合您的一种。

标签: c# asp.net asp.net-mvc nhibernate design-patterns


【解决方案1】:

你会怎么写这样的代码?

// Save both together or none of it
rep1.Save(newSomeEntity);
rep2.Save(SomeOtherEntity);

让它不在存储库中很容易

var rep1 = new Repository<SomeEntity>(session);
var rep2 = new Repository<SomeOtherEntity>(session);
using (var tx = session.BeginTransaction())
{
    try
    {
        rep1.Save(newSomeEntity);
        rep2.Save(SomeOtherEntity);
        tx.Commit();
    }
    catch (SomeException ex)
    {
        Handle(ex);
        tx.RollBack();
    }
}

【讨论】:

  • 我同意这一点。我唯一不同的想法是我有自己的 IUow,它有一个 NhUow 实现。 IUow 公开事务。原因是我不想在我的代码中直接引用 Nhib。所以很高兴将 NHIb 会话抽象为您自己的 Uow。
  • 我不知道你有自己的 UOW。我只是展示了问题中的实现无法完成的场景
  • 当然可以,但是您可以在存储库内部和外部引用会话/uow。
  • 很抱歉问的很明显,但什么是 UOW?我已经用谷歌搜索并关注了引用的 SO 文章,但找不到首字母缩写词代表什么......?
  • 意思是“工作单元”参见martinfowler.com/eaaCatalog/unitOfWork.html NHibernate 的 ISession 实现了这个模式