【发布时间】:2014-10-28 05:04:15
【问题描述】:
编辑
如果你把 10 位领域专家放在一个房间里会发生什么?对,你有 11 条意见。 (其中10个被声明为反模式)
感谢大家的详细解答。我会研究它们并考虑它们如何帮助我解决特定问题。
当与 ORM 和依赖注入一起使用时,我很难理解存储库和工作单元。考虑以下非常标准的接口:
public interface IRepository<TAggregateRoot> : ITransientDependency
{
void Add(TAggregateRoot aggregateRoot);
void Delete(TAggregateRoot aggregateRoot);
IEnumerable<TAggregateRoot> GetAll();
}
public interface IUnitOfWork : ITransientDependency
{
void Commit();
void Rollback();
}
我想用这些方法来介绍一些场景。
- 将单个实体插入到存储库中
- 删除链接实体也应删除的聚合
- 对超过 2 个存储库执行事务
使用 NHibernate 的默认实现可能如下所示:
public abstract class NHibernateRepository<TAggregateRoot> : IRepository<TAggregate>
{
protected NHibernateRepository(ISession session) {}
}
public sealed NHibernateUnitOfWork : IUnitOfWork
{
public NHibernateUnitOfWork(ISession session)
{}
public void Commit() {
_session.Flush();
}
}
1.场景:将单个实体插入存储库
// ASP.NET MVC controller, but valid for any
// other arbitary application service
public class MyController : Controller {
private readonly IPeopleRepository _repository;
// di -> declaring IPeopleRepository dependency
public MyController(IPeopleRepository repository) {
_repository = repository;
}
public void AddPerson(Person person) {
_repository.Add(person);
}
}
现在,在我将人添加到存储库后会发生什么?对,没什么。即使单个插入不完全是一个工作单元(一个事务,技术),像 EF 和 NHibernate 这样的 ORM 框架仍然需要提交对数据库的更改,因为他们花哨的会话和DBContexts在技术上是工作单元和存储库。
如何克服第一个问题?为我所做的每一件事开始一个工作单元?
2.Scenario:删除聚合,链接实体也应该被删除
查看以下汇总:
public class Person : IAggregateRoot {
private readonly List<Cat> _cats = new List<Cat>();
public IEnumerable<Cat> Cats {
get { return _cats; }
}
public void AddCat(Cat cat) {
//
}
让我们通过存储库使用它的根来删除聚合:
IPersonRepository.Remove(person);
现在,Person 聚合的所有实体都在技术上被删除。由于代码中不再有对它们的引用,因此垃圾收集器充当数据库管理器并从内存中删除 Cats。
但这在 ORM 存储库实现中看起来如何呢? 工作单元在哪里发挥作用?
3.场景:在超过 2 个存储库上进行事务
好的,我得到了我喜欢的 SomethingService。他必须在多个存储库上做一些事情,因此显然需要一个需要工作单元的事务。
public SomethingService : ISomethingService {
public ISomethingService(IFirstRepo repo1, ISecondRepo repo2, IUnitOfWork uow)
{
...
}
public void DoSomething() {
repo1.AddThis();
repo2.GetThisOne();
repo2.BecauseOfTheOneAboveDeleteThis();
uow.Commit();
}
}
对我来说看起来不错,但考虑到上面的 NHibernate 存储库和 工作单元 实现,这将不起作用,因为每个(工作单元、 2 个存储库)具有不同的 NHibernate 会话实例!
我考虑过使用 Interceptors 进行面向方面的编程,但这只是部分起作用,因为当 IoC 拦截服务方法时,已经使用自己的会话创建了存储库,因此无法共享工作单元的会话。
如何克服这个问题?是否有任何完整的工作示例可以在没有任何肮脏黑客的情况下运行? (例如,单件作品单元)
只是说:是的,我想将存储库与 ORM 一起使用。它们是一种很好的方式来抽象框架,让我按照我(或我的客户)想要的方式设计我的域,而不是像框架想要的那样。
非常感谢您阅读这堵文字墙。
【问题讨论】:
-
将实体添加到存储库应该也向 ORM 的更改跟踪器注册它。使用 EF,您可以通过将 repo 包装在 DbSet 周围来做到这一点。然后在进行任意数量的实体操作之后,您可以简单地调用
Commit,它映射到拥有 DbSet 的上下文的SaveChanges。不过,我认为您不能“将框架抽象掉”。
标签: c# entity-framework nhibernate dependency-injection domain-driven-design