首页 > 解决方案 > 两个聚合根之间的 DDD 共享实体

问题描述

我正在使用两个不同的聚合根:帖子和问题。它们都有一个类别。

到目前为止,我已经将它实现为一个共享实体(我不确定在 DDD 中是否是正确的设计)。

public class Post
{
    public Guid Id { get; private set; }

    public Category Category { get; private set; }

    public string Title { get; private set; }

    public string Body { get; private set; }
}

public class Question
{
    public Guid Id { get; private set; } 

    public Category Category { get; private set; }

    public string Title { get; private set; }

    public string Body { get; private set; }
}

public class Category
{
    public int Id { get; private set; }

    public string Name { get; private set; }

    public string Key { get; private set; }
}

注意:我知道我陷入了原始的痴迷反模式,并且我计划将这些原语重构为 ValueObjects。

读完这篇文章后DDD:共享具有多个聚合根的实体我想也许我应该将 Category 转换为 ValueObject (具有多个字段)。

理论上类别可能是一个拥有自己生命周期的实体,但现实是我并没有真正添加/删除/更新类别。

是否可以在 DDD 上使用共享实体?还是我最好使用ValueObject?

标签: entitydomain-driven-designaggregaterootvalue-objects

解决方案


让我们先处理一个聚合:发布

现在回答你的问题:

是否可以在 DDD 上使用共享实体?还是我最好使用ValueObject?

这取决于您将使用Category做什么。

场景一:

您的应用程序中有一个功能(或页面)来显示某个类别的所有帖子。我会采用以下设计:

public class Category
{
    public int Id { get; set; }
    //this is my in-memory database. Use repository and service to adjust yours
    public static List<Post> Posts;

    public Category()
    {
        Posts = new List<Post>();
    }

    public void AddPost(Guid id, string title, string body)
    {
        var post = new Post(id, title, body, this.Id);
        //saving the post into in-memory. Perhaps you can check some business logic inside Post entity
        Posts.Add(post);
    }

    // You can retrieve all posts of a single category
    public IEnumerable<Post> GetAllPosts()
    {
        return Posts.Where(x => x.CategoryId == this.Id);
    }
}

public class Post
{
    public Guid Id { get; private set; }
    public string Title { get; private set; }
    public string Body { get; private set; }
    public int CategoryId { get; private set; }

    public Post(Guid id)
    {
        Id = id;
    }

    public Post(Guid id, string title, string body, int categoryId)
    {
        //I prefer to pass guid into domain from external services.
        //Using this way, your service will have the id to return to upper layers.
        //Alternatively you can create new guid here on your own
        Id = id;
        Title = title;
        Body = body;
        CategoryId = categoryId;
    }

    // you can retrieve a post detail
    public Post GetPost()
    {
        return Category.Posts.FirstOrDefault(x => x.Id == this.Id);
    }
}

在这种情况下,我只能看到一个聚合根:Category

场景二:

您有帖子页面,用户可以从那里查看详细帖子。此外,每个帖子都有一个类别,该类别将显示在该详细页面的某个位置。你可以有以下简单的设计:

public class Post
{
    public Guid Id { get; private set; }
    public string Title { get; private set; }
    public string Body { get; private set; }
    public string CatKey { get; private set; }

    public Post(Guid id)
    {
        Id = id;
    }

    public Post(Guid id, string title, string body, string catKey)
    {
        //I prefer to pass guid into domain from external services.
        //Using this way, your service will have the id to return to upper layers.
        //Alternatively you can create new guid here on your own
        Id = id;
        Title = title;
        Body = body;
        //I don't even bother with category id. This is a simple value object, you can store all of your categories
        //into a hashtable of key-value
        CatKey = catKey;
    }

    // you can retrieve a post detail
    public Post GetPost()
    {
        //get your post detail from repo
    }
}

希望你现在可以做出决定。


推荐阅读