NHibernate ITransaction 和纯域模型

发布于 2024-08-03 20:33:54 字数 1185 浏览 10 评论 0原文

我正在尝试将我的域模型编写得尽可能不持久化。我现在唯一要做的就是将每个属性和方法标记为虚拟的,因为 NHibernate 需要这样做才能延迟加载。

在我的域模型程序集中,我定义了一些存储库接口:

public interface IRepository<TEntity> where TEntity : EntityBase {
    TEntity Get(int id);
    /* ... */
}
public interface IProductRepository : IRepository<Product> { ... }

然后我有一个数据程序集。这个将引用NHibernate,它知道它的存在。这是实现这些存储库接口的程序集:

public abstract class Repository<TEntity> : IRepository<TEntity> {
    public TEntity Get(ind id) { ... }
    /* ... */
}
public class ProductRepository : Repository<Product>, IProductRepository {
    /* ... */
}

等等。

现在我想为我的存储库实现事务功能。为此,我将在 IRepository 接口上添加一个 BeginTransaction 方法。但是,我无法将其返回类型定义为 NHibernate.ITransaction,因为我希望保持域模型持久性无知,并且不被迫从域模型程序集中引用 NHibernate 程序集。

你会怎么办?

您是否只需在接口上实现一个 void BeginTransaction()、一个 void Commit() 和一个 void RollBack() 方法,然后让存储库实现在内部管理ITransaction对象

或者您是否会找到一种方法来公开ITransaction对象,让客户端直接用它来管理事务,而不是使用存储库的方法?

谢谢!

I'm trying to write my Domain Model as persistence-ignorant as possible. The only thing I'm doing right now is marking every property and method virtual, as NHibernate requires that for lazy-loading.

In my domain model assembly I define some repository interfaces:

public interface IRepository<TEntity> where TEntity : EntityBase {
    TEntity Get(int id);
    /* ... */
}
public interface IProductRepository : IRepository<Product> { ... }

Then I have a data assembly. This one will reference NHibernate, it knows about its existence. This is the assembly that implements those repository interfaces:

public abstract class Repository<TEntity> : IRepository<TEntity> {
    public TEntity Get(ind id) { ... }
    /* ... */
}
public class ProductRepository : Repository<Product>, IProductRepository {
    /* ... */
}

and so on.

Now I wanted to implement a transaction functionality to my repositories. To do so, I would add a BeginTransaction method on my IRepository interface. However, I cannot define its return type as NHibernate.ITransaction, since I want to keep the domain model persistence-ignorant, and not be forced to reference NHibernate's assembly from my domain model assembly.

What would you do?

Would you simply implement a void BeginTransaction(), a void Commit(), and a void RollBack() methods on the interface, and let the repository implementation manage the ITransaction object internally?

Or would you find a way to expose the ITransaction object to let the client manage the transaction directly with it, instead of using repository's methods?

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

愁杀 2024-08-10 20:33:54

您可以查看 Sharp Architecture,它已经实现了您所讨论的所有内容,包括具有事务的通用存储库支持。解决方案是 IRepository 具有封装事务的 DbContext 属性(它实际上是一个接口)。
这是您描述的第一个选项(隐藏 NHibernate 的自定义事务接口)。而且效果很好。

我想无论您是否打算使用完整的框架,您甚至可以重复使用 S#arp 代码。

You can take a look at the Sharp Architecture which has already implemented everything you talk about, including generic repositories with transactions support. The solution there is that IRepository has DbContext property which encapsulates transactions (it's actually an interface).
This is the first of the options that you described (custom transactions interface which hides NHibernate). And it works well.

I guess you can even re-use S#arp code regardless if you intend to use the full framework.

不喜欢何必死缠烂打 2024-08-10 20:33:54

IMO 事务应该始终在业务逻辑中开始和结束,换句话说,事务应该在服务层而不是存储库层开始,并且存储库应该在事务中加入它自己,理想情况下这将隐式完成。

现在,如果您使用 NH,那么如果您的服务和存储库共享相同的“会话”(它们应该这样做),那么您可以在服务层中调用“BeginTransaction”并根据需要提交或回滚:

例如,想象这是一个方法一项服务:

 public void RegisterCustomer(客户客户)
    {
        尝试
        {
            使用(var transaction = _session.BeginTransaction())
            {
                _customerRepository.Save(客户);
                _customerSurveyRepository.Save(customerSurvey);
                // 做任何你想做的事...
                事务.Commit();
            }
        }
        catch(异常 exn)
        {
            抛出新的 AMException(FAILED_REGISTRATION, exn);
        }
     }

存储库如何获取对同一会话的引用可以通过注入构造函数或使用 SessionFactory 来获取当前会话来解决...

IMO Transactions should always start and end in business logic, in other words the transaction should start in the service layer not the repository layer and the repository should enlist it's self in the transaction, ideally this would be done implicitly.

Now if you're using NH then if your service and repositories share the same 'session' (which they should) then you can call 'BeginTransaction' in the service layer and commit or roll back as required:

Eg, imagine this a method on a service:

  public void RegisterCustomer(Customer customer)
    {
        try
        {
            using(var transaction = _session.BeginTransaction())
            {
                _customerRepository.Save(customer);
                _customerSurveyRepository.Save(customerSurvey);
                // DO What ever else you want...
                transaction.Commit();
            }
        }
        catch (Exception exn)
        {
            throw new AMException(FAILED_REGISTRATION, exn);
        }
     }

How the repositories obtain a reference to the same Session can be solved by injecting in the constructors or by using a the SessionFactory to obtain the current session...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文