我想我已经阅读了16,154个有关DDD和最佳做法的问题,博客文章,推文等。对于这个问题,我们深表歉意。假设我的数据库中有三个表:User,Department和UserDepartment。一切都很简单。我需要建立一个层次结构,显示用户可以访问哪些部门。问题在于,我还需要向他们展示可以访问的上级部门。
在我的用户类上最好有一个GetDepartments()方法吗?现在我有一个带有GetDepartments(string userName)的用户服务,但是我觉得那不是最佳解决方案。如果首选user.GetDepartments(),那么我如何访问存储库以获取用户有权访问的部门的父部门?
没关系,但我使用的是实体框架。
public class User
{
[Key]
public int UserId { get; private set; }
[Display(Name = "User Name")]
public string UserName { get; private set; }
[Display(Name = "Email")]
public string Email { get; private set; }
[Display(Name = "UserDepartments")]
public virtual ICollection<UserDepartment> UserDepartments { get; private set; }
public List<Department> GetDepartments()
{
// Should this be here? and if so, what's the preferred method for accessing the repository?
}
}
最佳答案
DDD的行为更多,这也意味着它是TDA(告诉,不要问)的。
通常,您以一种告诉他们该做什么而不要求信息的方式来构造聚合。
甚至,如果聚合需要某些额外的信息来执行其行为,那么通常通常也不希望弄清楚从何处获取此信息。
现在,当您说您的User聚合具有GetDepartments方法时,它会引起麻烦。集合是否需要此信息才能执行任何行为?我不这么认为,只是您要显示一些数据。
因此,我在这里看到的是您正在尝试根据数据表而不是根据行为来构造聚合。
在应用DDD时,这实际上是#2错误(#1不在考虑有限上下文)。
同样,聚合表示系统的业务逻辑和行为。这意味着您不必阅读汇总。您的读取端可以轻松完成-只需对数据库执行该死的查询即可。
但是一旦您需要让系统做某件事-现在您可以通过聚合来完成:AppService将从存储库中加载一个并调用其行为方法。
这就是为什么通常您的聚合中没有属性,而只是表示行为的方法的原因。
另外,您也不希望将聚合映射到数据表,这不是他们的工作,而是存储库的工作。实际上,您不希望您的域依赖于任何东西,尤其是基础架构。
因此,如果您想使用DDD方向,请考虑以下事项:
结构化汇总以封装行为,而不表示数据表
不要让您的域依赖于基础架构等。
使存储库负责加载/保存聚合。聚合自身不应该对持久性,数据结构等一无所知。
您不必通过聚合读取数据。
将#4视为系统有两个方面:当您仅读取数据并将其显示在UI中时为“读取”端,而在执行操作时为“命令”端。
第一个(读取)非常简单:愚蠢的查询以您想要的方式读取数据。它不影响任何东西,因为它只是阅读,在这里没有副作用。
第二个是您进行更改的时间,并且该更改正在您的域中进行。
同样,请记住DDD的第一条规则:如果没有要建模的业务逻辑和行为,则不要进行DDD。
关于domain-driven-design - DDD并在域类中获取其他信息,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20357374/