据我所知,Bounded Context可以有模块,模块可以有很多聚合根,聚合根可以有实体。对于持久性,每个聚合根应该有一个存储库。
在一个大型项目中有众多的聚合根,是否可以使用通用存储库,一个只用于准备就绪,一个用于更新?或者应该为每个聚合根提供单独的存储库,以便提供更好的控制。
答案 0 :(得分:4)
在一个大型复杂项目中,我不建议使用通用存储库,因为除了基本GetById()
,GetAll()
...操作之外,很可能会有很多特定情况。
Greg Young有一篇关于通用存储库的精彩文章:http://codebetter.com/gregyoung/2009/01/16/ddd-the-generic-repository/
是否可以使用Generic Repository,一个只用于就绪,一个用于更新?
存储库通常不处理保存实体的更新,即它们没有Update(EntityType entity)
方法。这通常由您的ORM的变更跟踪器/工作单元实施来处理。但是,如果您正在寻找一种将读写与写入分开的架构,那么您一定要查看CQRS。
答案 1 :(得分:1)
Pure DDD是关于隐式显式的,即:不使用List(),而是使用ListTheCustomerThatHaveNotBeSeenForALongTime()。
这里涉及的是技术实施。据我所知,域驱动设计不提供技术选择。
通用存储库非常适合。您对此通用存储库的使用可能不符合ddd的精神。这取决于您的域名。
答案 2 :(得分:1)
在Web上发布的一些示例DDD应用程序中,我看到它们有一个基本存储库接口,每个聚合根存储库都继承自该接口。我个人而言,做事情有点不同。因为存储库应该看起来像应用程序代码的集合,所以我的基本存储库接口继承自IEnumerable,所以我有:
public interface IRepository<T> : IEnumerable<T> where T : IAggregateRoot
{
}
我确实有一些基本方法,但是只有那些允许读取集合的方法,因为我的一些聚合根对象被封装到只能通过方法调用进行更改的点。
要回答您的问题,是的,拥有通用存储库是好的,但尽量不要定义任何不应由所有存储库继承的功能。而且,如果您不小心定义了一个存储库不需要的东西,请将其重构为所有需要它的存储库接口。
编辑:添加了如何使存储库的行为与任何其他ICollection对象一样的示例。
在需要CRUD操作的存储库中,我添加了这个:
void Add(T item); //Add
void Remove(T item); //Remove
T this[int index] { set; } //or T this[object id] { set; } //Update
答案 3 :(得分:0)
感谢您的评论。我采用的方法是将基本存储库接口分为ReadOnly和Updatable。每个聚合根实体都将拥有自己的存储库,并从Updatable或readonly存储库派生。聚合根级别的存储库将拥有自己的其他方法。我不打算使用通用存储库。
我选择使用IReadOnlyRepository是有原因的。将来,我会将应用程序的查询部分转换为CQRS。因此,对ReadOnly接口超类型的隔离将帮助我。