2

我有一个独特的情况,我正在构建一个需要访问Active Directory和SQL数据库作为持久性的基于DDD的系统。最初,这wasnt一个问题,因为我们的设计是建立在那里我们有一个看起来像这样的工作单元:在处理多个数据存储时,如何实现存储库模式和工作单元?

public interface IUnitOfWork 
{ 
    void BeginTransaction() 
    void Commit() 
} 

和我们的资料库是这样的:

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

在此设置我们的加载和保存将处理两个数据存储之间的映射,因为我们自己编写它。工作单元将处理事务,并将包含存储库将用于持久存储的Linq To SQL数据上下文。活动目录部分由基础架构中实施的域服务处理,并由每个Save()方法中的存储库使用。 Save()负责与数据上下文进行交互以执行所有数据库操作。

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

public interface IUnitOfWork 
{ 
    void BeginTransaction() 
    void Save() 
    void Commit() 
} 

public interface IRepository<T> 
{ 
    T GetByID() 
    void Add(T entity) 
    void Delete(T entity) 
} 

这解决了与实体框架数据访问的问题,但并没有解决我们的Active Directory集成的问题。之前,它在存储库的Save()方法中,但现在它没有家。工作单元除了实体框架数据上下文外什么都不知道。这个逻辑应该到哪里去?我认为这种设计只适用于只有一个数据存储使用实体框架的情况。任何想法如何最好地处理这个问题?我应该把这个逻辑放在哪里?

回答

4

我想回来后续跟进我发布以来学到的知识。看起来,如果您要保持存储库模式的真实性,那么它存储的数据存储并不重要。如果有两个数据存储区,请将它们写入同一个存储库。重要的是跟上存储库模式表示的外观:一个内存集合。我不会做单独的存储库,因为这对我来说不是一个真正的抽象。您正在让引擎盖下的技术决定当时的设计。引用来自dddstepbystep.com:

存储库背后是什么?漂亮 很多你喜欢的东西。是的,你听到 它是正确的。你可以有一个数据库, 或者你可以有许多不同的 数据库。您可以使用关系型数据库或对象数据库。你可以在内存数据库中有 ,或者 是一个包含 内存项目列表的单例。您可以有一个REST 图层或一组SOA服务或一个 文件系统或一个内存缓存...... 您可以拥有几乎任何东西 - 您唯一的限制是 存储库应该能够像 收藏到您的域名。这种灵活性是存储库与传统数据访问技术之间的关键差异 。

http://thinkddd.com/assets/2/Domain_Driven_Design_-_Step_by_Step.pdf

0

IMO我会将这些调用包装到这两个类的服务类型的回购。然后我将使用IoC/DI将回购类型注入服务类。你将有2个回购,1个为Ent。框架和支持AD的1。通过这种方式,每个回购仅处理其底层数据存储,并且不必交叉。

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

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

     IUnitOfWorkScope Get(bool shared); 
    } 

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

这使我可以将工作单元的不同实现注入到服务中,并且能够并排使用它们。

1

首先我假设你使用的是一个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); 
} 

CanPersist仅仅返回库实例是否支持持续传递的实体,并通过UnitOfWork.Save下面描述的多态使用。

每个IRepository也将有一个构造函数,允许IRepository以“事务性”模式构建。因此,对于EF,我们可能有:

public partial EFEntityARepository : IRepository<EntityA> { 
    public EFEntityARepository(EFContext context, bool transactional) { 
    _context = context; 
    _transactional = transactional; 
    } 
    public void Add(EntityA entity) { 
    _context.EntityAs.Add(entity); 
    if (!_transactional) _context.SaveChanges(); 
    } 
} 

的UnitOfWork应该是这样的:

interface UnitOfWork { 
    void Add(TEntity entity); 
    void Save(TEntity entity); 
    void Remove(TEntity entity); 
    void Complete(); 
} 

的实施的UnitOfWork将使用依赖注入来获得所有IRepository的实例。在UnitOfWork.Save/Add/Remove中,UoW会将参数实体传递给每个IRepository的CanPerist。对于任何返回值,UnitOfWork将把该实体存储在特定于该IRepository的私有集合中并且用于预期的操作。在Complete中,UnitOfWork将遍历所有私有实体集合,并针对每个实体在适当的IRepository上调用适当的操作。

如果你有一个实体需要被EF部分持久化并且被AD部分持久化,那么你将有两个IRepository类用于该实体类型(它们都会在传递该实体类型的实例时从CanPersist返回true) 。

至于保持EF和AD之间的原子性,这是一个单独的非平凡问题。

相关问题