我想我已经阅读了16,154个关于DDD和最佳实践的问题,博客文章,推文等。对这种类型的另一个问题道歉。假设我的数据库中有三个表,User,Department和UserDepartment。一切都很简单。我需要构建一个层次结构,显示用户可以访问哪些部门。问题是我还需要向他们有权访问的那些部门展示。
最好在我的用户类上使用GetDepartments()方法吗?现在我有一个GetDepartments用户服务(字符串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?
}
}
答案 0 :(得分:7)
DDD更多的是关于行为,这也意味着它是面向TDA(告诉,不要求)。
通常情况下,您构建聚合的方式是告诉他们要做什么,而不是询问以获取信息。
更重要的是,如果聚合需要一些额外的信息才能执行其行为,那么通常不会找出从哪里获取此信息。
现在,当您说您的用户聚合具有GetDepartments方法时,它会发出响铃。聚合是否需要此信息才能执行任何类型的行为?我不这么认为,只是你想要显示一些数据。
所以我在这里看到的是,您尝试针对数据表构建聚合,而不是针对行为。 应用DDD时,这实际上是#2 错误(#1 没有考虑有界上下文)。
同样,聚合表示系统的业务逻辑和行为。这意味着您不必从聚合中读取。您的阅读方可以更轻松地完成 - 只需向数据库发出一个该死的查询。
但是一旦你需要让你的系统做某事 - 现在你通过聚合来做:AppService会从存储库加载一个并调用它的行为方法。
这就是为什么通常你的聚合中没有属性,只有代表行为的方法。
此外,您不希望无论如何都要将聚合映射到数据表,这不是他们的工作,而是存储库的工作。实际上,您不希望您的域依赖于任何内容,尤其是基础架构。
因此,如果您想要寻找DDD方向,请考虑以下事项:
考虑#4,因为您的系统有两个方面:当您刚读取数据并在UI中显示它们时的“读取”方面,以及执行操作时的“命令”方面。
第一个(读取)非常简单:以您想要的方式读取数据的愚蠢查询。它不会影响任何东西,因为它只是阅读,没有副作用。
第二个是当您进行更改并且 正在通过您的域时。
再次,请记住DDD的第一条规则:如果您没有业务逻辑和行为来建模,那么就不要做DDD。