Domain driven design 在处理多个数据存储时,如何实现存储库模式和工作单元?

Domain driven design 在处理多个数据存储时,如何实现存储库模式和工作单元?,domain-driven-design,repository-pattern,unit-of-work,repository,ddd-repositories,Domain Driven Design,Repository Pattern,Unit Of Work,Repository,Ddd Repositories,我有一个独特的情况,我正在构建一个基于DDD的系统,需要访问Active Directory和SQL数据库作为持久性。最初这不是问题,因为我们的设计是在这样一个工作单元中设置的: public interface IUnitOfWork { void BeginTransaction() void Commit() } public interface IRepository<T> { T GetByID() void Save(T entity) v

我有一个独特的情况,我正在构建一个基于DDD的系统,需要访问Active Directory和SQL数据库作为持久性。最初这不是问题,因为我们的设计是在这样一个工作单元中设置的:

public interface IUnitOfWork
{
   void BeginTransaction()
   void Commit()
}
public interface IRepository<T>
{
   T GetByID()
   void Save(T entity)
   void Delete(T entity)
}
public interface IUnitOfWork
{
   void BeginTransaction()
   void Save()
   void Commit()
}

public interface IRepository<T>
{
   T GetByID()
   void Add(T entity)
   void Delete(T entity)
}
interface UnitOfWork {
  void Add(TEntity entity);
  void Save(TEntity entity);
  void Remove(TEntity entity);
  void Complete();
}
我们的存储库是这样的:

public interface IUnitOfWork
{
   void BeginTransaction()
   void Commit()
}
public interface IRepository<T>
{
   T GetByID()
   void Save(T entity)
   void Delete(T entity)
}
public interface IUnitOfWork
{
   void BeginTransaction()
   void Save()
   void Commit()
}

public interface IRepository<T>
{
   T GetByID()
   void Add(T entity)
   void Delete(T entity)
}
interface UnitOfWork {
  void Add(TEntity entity);
  void Save(TEntity entity);
  void Remove(TEntity entity);
  void Complete();
}
在这个设置中,我们的加载和保存将处理两个数据存储之间的映射,因为这是我们自己编写的。工作单元将处理事务,并包含存储库用于持久化的Linq到SQL数据上下文。active directory部分由基础结构中实现的域服务处理,并由每个保存方法中的存储库使用。Save负责与数据上下文交互以执行所有数据库操作

现在,我们正在尝试将其适应实体框架并利用POCO。理想情况下,我们不需要Save方法,因为域对象正在被对象上下文跟踪,我们只需要在工作单元上添加Save方法,让对象上下文保存更改,以及在上下文中注册新对象的方法。新提议的设计看起来更像这样:

public interface IUnitOfWork
{
   void BeginTransaction()
   void Commit()
}
public interface IRepository<T>
{
   T GetByID()
   void Save(T entity)
   void Delete(T entity)
}
public interface IUnitOfWork
{
   void BeginTransaction()
   void Save()
   void Commit()
}

public interface IRepository<T>
{
   T GetByID()
   void Add(T entity)
   void Delete(T entity)
}
interface UnitOfWork {
  void Add(TEntity entity);
  void Save(TEntity entity);
  void Remove(TEntity entity);
  void Complete();
}

这解决了实体框架的数据访问问题,但没有解决active directory集成的问题。以前,它位于存储库的Save方法中,但现在它没有主目录。工作单元只知道实体框架数据上下文。这种逻辑应该走向何方?我认为这种设计只有在只有一个使用实体框架的数据存储时才有效。如何最好地解决这个问题?我应该把这个逻辑放在哪里

IMO我将把对这两个repo的调用包装在类的服务类型中。然后我将使用IoC/DI将repo类型注入服务类。你将有2份回购协议,1份用于耳鼻喉科。框架和1支持AD。这样,每个回购协议只处理其底层数据存储,而不必交叉

我为支持多个工作类型单元所做的是让IUnitOfWork更像一个工厂。我创建了另一个名为IUnitOfWorkScope的类型,它是实际的工作单元,并且只有一个提交方法

namespace Framework.Persistance.UnitOfWork
{
    public interface IUnitOfWork
    {
        IUnitOfWorkScope Get();

        IUnitOfWorkScope Get(bool shared);
    }

    public interface IUnitOfWorkScope : IDisposable
{
    void Commit();
}
}

这允许我将工作单元的不同实现注入到服务中,并能够并行使用它们

首先,我假设您使用的是IoC容器。我主张为每种实体类型创建真正的存储库。这意味着您将把每个对象上下文EntitySet包装在一个类中,该类实现如下内容:

interface IRepository<TEntity> {
  TEntity Get(int id);
  void Add(TEntity entity);
  void Save(TEntity entity);
  void Remove(TEntity entity);
  bool CanPersist<T>(T entity);
}
UnitOfWork实现将使用依赖项注入来获取所有IRepository的实例。在UnitOfWork.Save/Add/Remove中,UoW将参数实体传递到每个IRepository的CanPerist中。对于任何真正的返回值,UnitOfWork将该实体存储在特定于该IRepository和预期操作的私有集合中。完成后,UnitOfWork将遍历所有私有实体集合,并为每个实体调用相应IRepository上的相应操作

如果您有一个实体需要由EF部分持久化,由AD部分持久化,那么该实体类型将有两个IRepository类,当传递该实体类型的实例时,它们都将从CanPersist返回true


至于保持EF和AD之间的原子性,这是一个独立的非琐碎问题。

我想回来继续我在发布本文后学到的东西。看起来,如果您要保持对存储库模式的忠实,那么它所坚持的数据存储并不重要。如果有两个数据存储,则在同一存储库中写入它们。重要的是保持存储库模式所代表的外观:内存中的集合。我不会做单独的存储库,因为我觉得这不是一个真正的抽象。你让引擎盖下的技术决定了当时的设计。引用dddstepbystep.com:

存储库后面是什么?漂亮的 你喜欢什么都行。是的,你听到了 没错。你可以有一个数据库, 或者你可以有很多不同的 数据库。您可以使用关系数据库 数据库或对象数据库。你 可能有内存中的数据库,或者 一个包含一个列表的单件 内存项。你可以休息一下 层,或一组SOA服务,或 文件系统或内存缓存… 你几乎可以拥有任何东西—— 你唯一的限制是 存储库应该能够像 将集合添加到您的域。这 灵活性是一个关键区别 在存储库和传统数据库之间 数据存取技术