Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/asp.net/30.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 一个聚合根是否可以包含嵌套的子级?_C#_Asp.net_Domain Driven Design - Fatal编程技术网

C# 一个聚合根是否可以包含嵌套的子级?

C# 一个聚合根是否可以包含嵌套的子级?,c#,asp.net,domain-driven-design,C#,Asp.net,Domain Driven Design,两个月前,我买了Scott Millet的《专业ASP.NET设计模式》一书,因为我想学习如何使用设计模式构建分层web应用程序。我在自己的应用程序中使用了这本书中的案例研究,所以一切都设置好了 我的问题是,我不确定我的总根 我有一个可以创建集合的用户。用户可以向集合中添加类别,并向类别中添加关键字。在我的数据库中看起来是这样的: - Users - PK: UserId - Collections - PK: CollectionId - FK: UserId -

两个月前,我买了Scott Millet的《专业ASP.NET设计模式》一书,因为我想学习如何使用设计模式构建分层web应用程序。我在自己的应用程序中使用了这本书中的案例研究,所以一切都设置好了

我的问题是,我不确定我的总根

我有一个可以创建集合的用户。用户可以向集合中添加类别,并向类别中添加关键字。在我的数据库中看起来是这样的:

- Users
    - PK: UserId

- Collections
    - PK: CollectionId
    - FK: UserId

- Categories
    - PK: CategoryId
    - FK: CollectionId

- Keywords
    - PK: KeywordId
    - FK: CategoryId
我不认为让用户成为集合的聚合根是合乎逻辑的,但类别和关键字一起构成了一个集合。所以我将用户设置为一个聚合根,它还没有子级,而将集合设置为一个聚合根。单个集合可以有多个类别,类别可以有多个关键字。因此,当我想添加一个类别时,我会这样做:

public void CreateCategory(CreateCategoryRequest request)
    {
        Collection collection = _collectionRepository.FindCollection(request.IdentityToken, request.CollectionName);

        Category category = new Category { Collection = collection, CategoryName = request.CategoryName };

        ThrowExceptionIfCategoryIsInvalid(category);

        collection.AddCategory(category);

        _collectionRepository.Add(collection);
        _uow.Commit();
    }
这很好,但是当我想添加关键字时,我首先需要获取集合,然后获取类别,在该类别中我可以添加关键字,然后提交集合:

public void CreateKeyword(CreateKeywordRequest request)
    {
        Collection collection = _collectionRepository.FindCollection(request.IdentityToken, request.CollectionName);

        Category category = collection.Categories.Where(c => c.CategoryName == request.CategoryName).FirstOrDefault();

        Keyword keyword = new Keyword { Category = category, KeywordName = request.KeywordName, Description = request.KeywordDescription };

        category.AddKeyword(keyword);

        _collectionRepository.Add(collection);
        _uow.Commit();
    }

这让我觉得不对(是吗?)是什么让我相信我应该把category作为关键字的聚合根。但这又提出了另一个问题:像我在第一个代码示例中所做的那样,我拥有一个创建类别聚合的集合聚合是否仍然有效?示例:collection.Add(category)

这可能感觉不太对,因为添加一个新关键字需要从集合引用开始,而完全可以从类别引用开始。当用户添加关键字时,他肯定会在类别的上下文中添加关键字,因此您当时可能在内存中有该类别

另外,我没有在每个
Add[SomeSubEntity]()
方法的末尾获得
\u collectionRepository.Add(collection)
。集合应该已经存在于存储库中,所以您只需保存它,对吗


至于嵌套的聚合,我发现它有点复杂,与两个单独的聚合(类别和集合)相比,并没有真正看到它的好处。

聚合根肯定可以包含嵌套的子级,但是如果这些子级也是聚合,这可能是一个警告,表明聚合可能做得太多了。在您的例子中,我认为
集合
是一个聚合,而
类别
不是,它只是属于
集合
聚合的一个实体,甚至是一个值对象,它恰好包含
关键字
实例,这些实例也是值对象

我将更改实现,使
CreateCategory
服务方法看起来更像这样:

public void CreateCategory(CreateCategoryRequest request)
{
        var collection = _collectionRepository.Get(request.IdentityToken, request.CollectionName);

        collection.AddCategory(request.CategoryName);

        _uow.Commit();
}
Collection
上的
AddCategory
方法负责创建
Category
实例以及错误检查。这是有意义的,因为它是聚合根,负责管理它所包含的实体和值对象的集群。没有对存储库上的Add方法的调用,因为环境工作单元应该提交更改

我将更改
CreateKeyword
方法,使其看起来更像:

public void CreateKeyword(CreateKeywordRequest request)
{
        var collection = _collectionRepository.Get(request.IdentityToken, request.CollectionName);

        collection.AddKeyword(request.CategoryName, request.KeywordName, request.KeywordDescription);

        _uow.Commit();
}
Collection
上的
AddKeyword
方法检索相应的
类别
,然后向其添加关键字,如果需要,抛出异常以增强一致性和有效性

如您所见,这两个方法有一个模式——首先通过键检索聚合,然后调用聚合上的方法,最后提交所有内容。通过这种方式,聚合可以更好地控制它们自己的状态,您可以避免出现错误并减少服务中存在的代码量


对于骨料设计的深入处理,请看。

在这种情况下,一个简单的经验法则是考虑“在集合之外有一个类别是否有意义?”如果不是,将类别设为单独的根并没有多大意义。我考虑过这一点,因为我在一个页面上显示集合,在另一个页面上显示带有关键字的类别。但是,即使它不是聚合根,通过类别对象添加关键字仍然是有意义的吗?类别在集合之外具有标识有意义吗?也就是说,如果两个用户使用相同的名称添加了一个类别,那么他们是集合的本地用户还是在用户之间共享的?他们是集合的本地用户。您对_collectionRepository.add(集合)的看法是正确的。这没有道理。我还是一个初学者,所以我可能读过一些东西。用户首先添加一个类别。创建一个关键字后,他或她可以选择是否添加关键字。因此,我可以在集合存储库中创建一个方法,返回一个类别,并向该类别添加一个关键字。对吗?在我看来,您不需要返回类别的方法。只需保留新创建的Category实例并向其添加关键字即可。然后提交您的工作单元,将所有内容保存到数据库中。感谢您的明确解释。这是一种方法,但它也有缺点,比如因为所有实体的AddSomething()方法都必须填充到它中,所以它有一个膨胀的God对象聚合根。相反,您可能会意识到您的CreateKeywordRequest已经包含该类别,因此您可以在不使用Collection的情况下执行Category.AddKeyword()。但是我的Category对象有一个对集合的引用来指示NHbibernate中的外键,而我的CreateKeywordRequest中没有该外键。所以当我想通过分类添加关键字时,我仍然需要集合,对吗?我只有获取集合和类别的字符串。@guillaume31-我相信所有这些方法都是一件好事,因为它们实现了封装。然而,在这种情况下,aggre