领域驱动设计:何时创建聚合根?

发布于 2024-08-06 19:25:57 字数 593 浏览 4 评论 0原文

我第一次尝试在 ASP.NET MVC 项目中实现 DDD,但我遇到了一些困难。

我有 2 个相关实体:一家公司和一家供应商。我最初的想法是,Company 是一个聚合根,Supplier 是 Company 的一个价值对象。所以我有一个公司的存储库,但没有供应商的存储库。

但当我开始构建我的应用程序时,我最终需要为供应商单独列出、创建和更新表单。该列表很容易,我可以调用 Company.Suppliers,创建很糟糕,我可以做 Company.Suppliers.Add(supplier),但更新让我头疼。由于我只需要一个实体,并且无法将其准确地保存在表单之间的内存中,因此我最终需要重新获取公司和所有供应商,找到我需要绑定到它的实体,然后再次修改它并保留它回到数据库。

如果我有供应商的存储库,我真的只需要执行 GetOne。我可以通过将 GetOneSupplier 添加到我的 Company 或 CompanyRepository 来添加一些解决方法,但这看起来很垃圾。

所以,我真的想知道它是否实际上是一个值对象,而不是一个完整的域实体本身。

tldr;

需要单独的列表/创建/更新视图/页面是否表明实体应该是它自己的根?

I'm attempting to implement DDD for the first time with a ASP.NET MVC project and I'm struggling with a few things.

I have 2 related entities, a Company and a Supplier. My initial thought was that Company was an aggregate root and that Supplier was a value object for Company. So I have a Repository for company and none for Supplier.

But as I have started to build out my app, I ended up needing separate list, create, and update forms for the Supplier. The list was easy I could call Company.Suppliers, and create was horrible I could do Company.Suppliers.Add(supplier), but update is giving me a headache. Since I need just one entity and I can't exactly stick it in memory between forms, I ended up needing to refetch the company and all of the suppliers and find the one I needed to bind to it and again to modified it and persist it back to the db.

I really just needed to do a GetOne if I had a repository for Supplier. I could add some work arounds by adding a GetOneSupplier to my Company or CompanyRepository, but that seems junky.

So, I'm really wondering if it's actually a Value Object, and not a full domain entity itself.

tldr;

Is needing separate list/create/update view/pages a sign that an entity should be it's own root?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

迟到的我 2024-08-13 19:25:57

根据您的术语,我假设您正在根据 Eric Evans 的书执行 DDD。听起来您已经在最初的建模过程中发现了一个问题,而且您是对的。

您提到您认为供应商是一个值对象...我认为事实并非如此。 值对象主要由其属性来标识。例如,日期“2009年9月30日”就是一个值对象。为什么?因为具有不同月/日/年组合的所有日期实例都是不同的日期。具有相同月/日/年组合的所有日期实例都被视为相同。我们永远不会争论将我的“2009 年 9 月 30 日”换成你的,因为它们是相同的:-)

另一方面,实体 主要由其“ID”标识。例如,银行账户有 ID——它们都有帐号。如果银行有两个账户,每个账户有 500 美元,如果它们的账号不同,那么它们也不同。它们的属性(在本例中为它们的平衡)并不识别它们或暗示相等。我敢打赌,即使银行账户的余额相同,我们也会争论交换银行账户:-)

因此,在您的示例中,我会将供应商视为实体,因为我假设每个供应商主要由它的 ID 而不是它的属性。我自己的公司与世界上另外两家公司同名——但我们不能互换。

我认为您的建议是,如果您需要对对象进行 CRUD 的视图,那么它是一个 Entity 作为经验法则可能是正确的,但您应该更多地关注使一个对象与其他对象不同的原因:属性或ID。

现在就聚合根而言,您需要关注对象的生命周期和访问控制。考虑一下我有一个博客,其中有很多帖子,每个帖子都有很多评论 - 聚合根在哪里?让我们从评论开始。没有帖子就发表评论有意义吗?您会创建一条评论,然后找到一篇帖子并将其附加到其中吗?如果您删除帖子,您会保留其评论吗?我建议一篇文章是一个带有一个“叶子”的聚合根 - 评论。现在考虑博客本身 - 它与其帖子的关系类似于帖子和评论之间的关系。在我看来,它也是一个带有一个“叶子”的聚合根 - 帖子。

因此,在您的示例中,公司和供应商之间是否存在牢固的关系,如果您删除一家公司(我知道......您可能只有一个公司实例),您也会删除其供应商吗?如果删除“星巴克”(美国的一家咖啡公司),它的所有咖啡豆供应商都会不复存在吗?这一切都取决于您的域和应用程序,但我建议您的实体很可能都不是聚合根,或者也许考虑它们的更好方法是它们是聚合根,每个根没有“叶子”(没有可聚合的内容)。换句话说,公司不控制供应商的访问或控制其生命周期。它与供应商之间只是一对多的关系(或者可能是多对多的关系)。

这将我们带到存储库存储库用于存储和检索聚合根。您有两个(从技术上讲,它们不会聚合任何内容,但它比说“存储库存储聚合根或不是聚合中的叶子的实体”更容易),因此您需要两个存储库。一份给公司,一份给供应商。

我希望这有帮助。也许埃里克·埃文斯潜伏在这里,会告诉我我在哪里偏离了他的范式。

Based on your terminology I assume you are performing DDD based on Eric Evans' book. It sounds like you have already identified a problem with your initial go at modeling and you are right on.

You mention you thought of supplier as a Value Object... I suggest it is not. A Value Object is something primarily identified by its properties. For example, the date "September 30th, 2009" is a value object. Why? Because all date instances with a different month/day/year combo are different dates. All date instances with the same month/day/year combo are considered identical. We would never argue over swapping my "September 30th, 2009" for yours because they are the same :-)

An Entity on the other hand is primarily identified by its "ID". For example, bank accounts have IDs - they all have account numbers. If there are two accounts at a bank, each with $500, if their account numbers are different, so are they. Their properties (in this example, their balance) do not identify them or imply equality. I bet we would argue over swapping bank accounts even if their balances were the same :-)

So, in your example, I would consider a supplier an Entity, as I would presume each supplier is primarily identified by its ID rather than its properties. My own company shares its name with two others in the world - yet we are not all interchangeable.

I think your suggestion that if you need views for CRUDing an object then it is an Entity probably holds true as a rule of thumb, but you should focus more on what makes one object different from others: properties or ID.

Now as far as Aggregate Roots go, you want to focus on the lifecycle and access control of the objects. Consider that I have a blog with many posts each with many comments - where is/are the Aggregate Root(s)? Let's start with comments. Does it make sense to have a comment without a post? Would you create a comment, then go find a post and attach it to it? If you delete a post, would you keep its comments around? I suggest a post is an Aggregate Root with one "leaf" - comments. Now consider the blog itself - its relationship with its posts is similar to that between posts and comments. It too in my opinion is an Aggregate Root with one "leaf" - posts.

So in your example, is there a strong relationship between company and supplier whereby if you delete a company (I know... you probably only have one instance of company) you would also delete its suppliers? If you delete "Starbucks" (a coffee company in the US) do all its coffee bean suppliers cease to exist? This all depends on your domain and application, but I suggest more than likely neither of your Entities are Aggregate Roots, or perhaps a better way to think about them is that they are Aggregate Roots each with no "leaves" (nothing to aggregate). In other words, company does not control access to or control the lifecycle of suppliers. It simply has a one-to-many relationship with suppliers (or perhaps many-to-many).

This brings us to Repositories. A Repository is for storing and retrieving Aggregate Roots. You have two (technically they are not aggregating anything but its easier than saying "repositories store aggregate roots or entities that are not leaves in an aggregate"), therefore you need two Repositories. One for company and one for suppliers.

I hope this helps. Perhaps Eric Evans lurks around here and will tell me where I deviated from his paradigm.

究竟谁懂我的在乎 2024-08-13 19:25:57

对我来说听起来很简单 - 供应商应该有自己的存储库。如果存在任何逻辑上的可能性,即实体可以独立存在于模型中,那么它应该是根实体,否则您最终将在稍后进行重构,这是多余的工作。

尽管需要预先进行额外的实现工作,但根实体始终比值对象更灵活。我发现随着模型的发展,模型中的值对象会变得越来越稀有,而保留值对象的实体通常是您可以从第一天开始就以这种方式进行逻辑约束的实体。

如果公司共享供应商,那么将供应商作为根实体也会消除数据冗余,因为您不会重复每个公司的供应商定义,而是共享引用,并且公司和供应商之间的关联也可以是双向的,这可能会导致数据冗余。产生更多的效益。

Sounds like a no-brainer to me - Supplier should have its own repository. If there is any logical possibility that an entity could exist independently in the model then it should be a root entity, otherwise you'll just end up refactoring later on anyway, which is redundant work.

Root entities are always more flexible than value objects, despite the extra implementation work up front. I find that value objects in a model become rarer over time as the model evolves, and entities that remain value objects were usually the ones that you could logically constrain that way from day one.

If companies share suppliers then having supplier as a root entity removes data redundancy as well, as you do not duplicate the supplier definition per company but share the reference instead, and the association between Company and Supplier can be bi-directional as well, which may yield more benefits.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文