DDD并在域类中获取其他信息

时间:2013-12-03 17:07:55

标签: domain-driven-design ddd-repositories

我想我已经阅读了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?
    }
}

1 个答案:

答案 0 :(得分:7)

DDD更多的是关于行为,这也意味着它是面向TDA(告诉,不要求)。

通常情况下,您构建聚合的方式是告诉他们要做什么,而不是询问以获取信息。

更重要的是,如果聚合需要一些额外的信息才能执行其行为,那么通常不会找出从哪里获取此信息。

现在,当您说您的用户聚合具有GetDepartments方法时,它会发出响铃。聚合是否需要此信息才能执行任何类型的行为?我不这么认为,只是你想要显示一些数据。

所以我在这里看到的是,您尝试针对数据表构建聚合,而不是针对行为。 应用DDD时,这实际上是#2 错误(#1 没有考虑有界上下文)。

同样,聚合表示系统的业务逻辑行为。这意味着您不必从聚合中读取。您的阅读方可以更轻松地完成 - 只需向数据库发出一个该死的查询。

但是一旦你需要让你的系统某事 - 现在你通过聚合来做:AppService会从存储库加载一个并调用它的行为方法。

这就是为什么通常你的聚合中没有属性,只有代表行为的方法

此外,您不希望无论如何都要将聚合映射到数据表,这不是他们的工作,而是存储库的工作。实际上,您不希望您的域依赖于任何内容,尤其是基础架构。

因此,如果您想要寻找DDD方向,请考虑以下事项:

  1. 构建聚合以封装行为,而不是表示数据表
  2. 不要让您的域名依赖于基础设施等。
  3. 使存储库负责加载/保存聚合。聚合本身应该对持久性,数据结构等一无所知。
  4. 您不必通过聚合读取数据。
  5. 考虑#4,因为您的系统有两个方面:当您刚读取数据并在UI中显示它们时的“读取”方面,以及执行操作时的“命令”方面。

    第一个(读取)非常简单:以您想要的方式读取数据的愚蠢查询。它不会影响任何东西,因为它只是阅读,没有副作用。

    第二个是当您进行更改并且 正在通过您的域时。

    再次,请记住DDD的第一条规则:如果您没有业务逻辑和行为来建模,那么就不要做DDD。