实体访问存储库可以吗?

我刚刚开始使用DDD,所以也许这是一个愚蠢的问题…

一个实体访问一个仓库(通过一些IRepository接口)在运行时获取一个值可以吗? 例如,我想强制执行一个属性的“默认”select:

class Person { private Company _employer; public Company Employer { get { return _employer; } set { if(value != null) { _employer = value; } else { _employer = employerRepository.GetDefaultEmployer(); } } } ... } 

我的问题是,这样做是否违反了DDD的原则。 如果不是,我的下一个问题将是提供存储库使用的最佳方式是什么? 是否在Person对象创build时提供?

谢谢,P

这不是一个可怕的违反DDD这是一个可怕的违反…好吧…这只是平原可怕(我说这个舌头):)。

首先,你的实体变得依赖于存储库…这不是理想的。 理想情况下,您希望让您的存储库创buildPerson,然后为其分配当前域环境中需要的所有function。

所以,当你需要一个人,你会去personRepository.GetPersonWithDefaultEmployer()并找回一个人有一个默认的雇主填充。 personRepository将对雇主信息库具有依赖关系,并在返回之前使用它来填充该人员。

 PersonReposotory : IPersonRepository { private readonly IEmployerRepository employerRepository; //use constructor injection to populate the EmployerRepository public PersonRepository(IEmployerRepository employerRepository) { this.employerRepository = employerRepository; } public person GetPersonWithDefaultEmployer(int personId) { Person person = GetPerson(personId); person.Employer = employerRepository.GetDefaultEmployer(personId); return person; } } 

对你的问题sorting的答案是的标准。

作为一个经验法则,永远不要这样做。 保持你的实体没有引用存储库。 [ 把实用的帽子放在 ]在一些罕见的,极其罕见的情况下,你有这样一个非常非常好的理由,而不是添加一个重要的评论,解释你为什么要这样做,做到这一点 – 添加引用或使用“ 双重调度”存储库[ 帽子closures ]

另外,如果你想遵循DDD的原则,强烈build议你有机会获得一个领域的专家和一个迭代的开发过程(见埃里克·埃文斯 – 自从书以来我学到了什么 )。

有了领域专家,您应该定义边界上下文,最重要的是定义聚合及其聚合根,实体和值对象。 开始DDD的道路一开始并不容易,但是这些词汇是可以接受的。

关于您发布的代码的一些事情:

  1. 不build议在你的实体上有公共设置者。 使用方法,而不是更好地expression意图。

  2. 如果没有初始化_employer字段而创buildperson实例,则Employer属性的getter将返回null。 如果您然后将Employer属性的值设置为null,则下一次对getter的调用将返回非空值。 这可能是您的class级的用户意想不到的。

  3. 调用者设置Person的雇主(通过公共设置者或公共方法)应该知道确切的Company实例,即使它是默认设置。 也许调用者可以有对存储库的引用。

  4. 根据您的具体领域,公司可能是一个价值对象。 在这种情况下,您可以使用null值初始化_employer,而不是使用value对象的默认值进行初始化。 如果你只有很less的公司(1-2),并且它们是不可改变的并且没有特定的行为,那么情况就是这样。

我认为很容易说一个实体不应该知道存储库,但很难把它付诸实践。 特别是当一个聚集内部有大量的vo的集合时,我们必须重构它,并委托像添加到某个实际充当存储库的域服务一样的操作,以避免将整个集合加载到内存中的开销。
但是我认为让实体知道存储库是不合理的。 如果我们必须这样做,那么就使用域服务 。我们还应该考虑一个存储库是否违反单一责任原则 – 它应该被认为是聚合根的集合,而不是正常的工厂

是不是真的推荐使用ddd?

而如果你没有内存中的仓库,而是你的仓库的关系数据库,你想要雇用1000人? 你打算通过employerRepository调用1000个查询吗?

我会使用NHibernate或任何ORM来帮助实现personRepository。 在NHibernate中,我将使用Hibernate Query来接近这个:“Person join Fetch Employer”,它将在每个“Person”实例中加载一个“Employer”实例,只有一个SQL查询。

这是DDD违规吗?

首先,我认为实体本身以及如何组装实体实际上是两项职责。 所以最好把它们分配到不同的课堂上。 但这也取决于。