How to design great Aggregate Roots in Domain-Driven Design

  Рет қаралды 18,486

Milan Jovanović

Milan Jovanović

Күн бұрын

Пікірлер: 58
@MilanJovanovicTech
@MilanJovanovicTech 8 ай бұрын
Want to master Clean Architecture? Go here: bit.ly/3PupkOJ Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt
@vantavoids
@vantavoids 8 ай бұрын
honestly the fact that i was struggling all day with my aggregate roots and you happen to release a video talking about those specially... did you hide a mic under my desk?? other than that top tier video as per usual please keep it up
@MilanJovanovicTech
@MilanJovanovicTech 8 ай бұрын
Glad it was helpful, and no worries I don't have a mic anywhere (or do I?)
@enricoroselino7557
@enricoroselino7557 3 ай бұрын
milan sure have mic everywhere 😂
@sergiom.954
@sergiom.954 8 ай бұрын
The value of your content is unique. Thanks Milan
@MilanJovanovicTech
@MilanJovanovicTech 8 ай бұрын
No, thank you! :)
@ferventurart
@ferventurart 8 ай бұрын
Great Milan, your explain a complex concept in a simple example! 👏
@MilanJovanovicTech
@MilanJovanovicTech 8 ай бұрын
Glad you liked it!
@mreshboboyev
@mreshboboyev 2 ай бұрын
most, most awesome content, thank you!
@MilanJovanovicTech
@MilanJovanovicTech 2 ай бұрын
Glad you think so!
@wannadie9950
@wannadie9950 8 ай бұрын
awesome job milan, love you
@MilanJovanovicTech
@MilanJovanovicTech 8 ай бұрын
Thanks a lot! :)
@MdSayeedRahman-h3e
@MdSayeedRahman-h3e 5 ай бұрын
Great content!
@MilanJovanovicTech
@MilanJovanovicTech 5 ай бұрын
Thanks a lot :)
@davidjiang7929
@davidjiang7929 8 ай бұрын
Would you happen to have more examples on the unit of work and how to save aggregate to database?
@MilanJovanovicTech
@MilanJovanovicTech 8 ай бұрын
Well, I've got a bunch of videos on the channel covering DDD aggregates directly or indirectly
@thomaswoods1365
@thomaswoods1365 7 ай бұрын
Milan I implemented this full model and got update exceptions. I want to be able to add and delete within the aggregated tables but every add I do is recorded as a changestate modified not an insert. Is there some way to have it work correctly? I confirmed that if I use the dbContext and add directly to the entity object it is in a change state of Added. If I do not use the dbContext and add inside the aggregate root it is set to Modified.
@MilanJovanovicTech
@MilanJovanovicTech 7 ай бұрын
What is the "it" that's set to modified?
@thomaswoods1365
@thomaswoods1365 7 ай бұрын
@@MilanJovanovicTech the "it" is a child table. Example: Orders and OrderDetails. If I create an add method for OrderDetails in Orders aggregate root, as you have defined in your example, the add produces a change state Modified not Added. Throws a DbUpdateConcurrency exception because the row is not in the database yet. If Aggregate Root pattern does not intend to be used like this please let me know. In your example I'm doing exactly as you are adding an exercise to the workout aggregate root. If yours works and mine throws an exception I'm not sure why.
@thomaswoods1365
@thomaswoods1365 7 ай бұрын
I just did some deeper study on AggRoots. I get the feeling that AggRoot concept by definition requires that all records within the aggregate be created at the same time because of the interdependency that justifies the AR implementation. In the case of Order/OrderDetail it may be that it is NOT an AR model. Would like to get your opinion on that.
@thomaswoods1365
@thomaswoods1365 7 ай бұрын
Milan I have double checked the code. When you pushed down the Remove for exercise it deletes from the exercise collection within Workout domain object then you call SaveChanges(). The problem is the exercise collection is not tracked by EF. There is no insert getting written to the database for the Exercise added. This model of having an internal collection for the non-root aggregates is broken as I see it. There is no reference to the repository either, thus no way to cause the insert to occur. What is the right way to get an aggregate member inside the aggregate root to perform CRUD correctly?
@thomaswoods1365
@thomaswoods1365 7 ай бұрын
Ok, I have the answer to this issue in case it is helpful to anyone else. If the entity you add to the collection has an ID assigned it will treat it as an UPDATE and change state will be set by EF to Modified. I removed the ID and it accurately set the change state to Added. The problem here Milan is that the entity base classes are not allowing nullable ID's, which means you will ALWAYS get a Modified state and never a Added state. I don't know what this means to the base classes you have defined Milan. I would love to understand if there is a better way to successfully handle this. I had to set every property inside all entities to nullable in order to get the right behaviors. I do not think that is necessarily a good thing.
@pvlzh
@pvlzh 4 ай бұрын
Thanks for the video. In the example, you started taking the entity id instead of the entity itself to delete the record (link record). But what if I need to add a link to an existing entity? Is it right that in this case it will have to be obtained from outside and there is no other option?
@MilanJovanovicTech
@MilanJovanovicTech 4 ай бұрын
Yes, correct
@alexramossilva
@alexramossilva 8 ай бұрын
Can you talk about Business Rule Engines and what are the design patterns appropriate to implement it?
@MilanJovanovicTech
@MilanJovanovicTech 8 ай бұрын
Not familiar with them
@vuhoang5903
@vuhoang5903 3 ай бұрын
Should I let an aggregate reference an entity inside another aggregate but not go through the root? For example Restaurant has Menu which has a list of Dish. Coupon Aggregate has a scope that is applicable to specific dishes so there should be a collection of applicable dish ids in the coupon aggregate right?
@MilanJovanovicTech
@MilanJovanovicTech 3 ай бұрын
Yes, that is acceptable. Holding references (IDs) to other entities is fine.
@BlindVirtuoso
@BlindVirtuoso 8 ай бұрын
Hi Milan. Nice video, appreciate it. Though not so good example on Workout aggregate, not showing any invariant between Workout and Exercises. Aggregate is about behavior and invariants and not about data.
@MilanJovanovicTech
@MilanJovanovicTech 8 ай бұрын
Wanted to focus on maintaining a consistency boundary
@JonathanW-k6c
@JonathanW-k6c 4 ай бұрын
Sorry for asking another question about my previous problem (multiple prices in different currencies for products, shipping methods, and other aggregates). Could you give me a hint, if I had to choose between aggregates and child entities (for each aggregate with prices) to represent price, which one should I prefer?
@MilanJovanovicTech
@MilanJovanovicTech 4 ай бұрын
I don't know man 😅 This type of modeling question requires much more context than could fit in a YT comment.
@Luke_Ainsworth
@Luke_Ainsworth 5 ай бұрын
Hey Milan, Great video! I notice in some of your other examples around Aggregate Roots, you'll use an aggregate root class which is just an entity that handles your domain event logic as-well. Have you moved away from Aggregate Root classes/marker interfaces?
@MilanJovanovicTech
@MilanJovanovicTech 5 ай бұрын
Yes, correct. I just have an entity with domain events inside. The aggregate is enforced as logical concept in my design. Not much value in having an explicit class/interface.
@JonathanW-k6c
@JonathanW-k6c 4 ай бұрын
Hey, nice video! What if I need store prices for the products, shipping methods, and some other aggregates in different currencies (country, currency, and amount)? Should I store it as a list of value objects for each entity, child entities or maybe separate aggregates?
@MilanJovanovicTech
@MilanJovanovicTech 4 ай бұрын
That would depend on how much information we're storing. If the lists are bounded (finite # of elements), that could be a viable option.
@mahmoudali1660
@mahmoudali1660 7 ай бұрын
What do you mean by the use case? Thank you
@MilanJovanovicTech
@MilanJovanovicTech 7 ай бұрын
A component providing the desired functionality for one feature
@victorgarcia3526
@victorgarcia3526 8 ай бұрын
Hey Milan, what if you push your code examples to github so we can check the code while watching the video?
@MilanJovanovicTech
@MilanJovanovicTech 8 ай бұрын
I share the code on Patreon
@maxencemartin6498
@maxencemartin6498 5 ай бұрын
Hi Milan, thank for your video. Juste a question remaining in my mind. Does this mean that we have to pass through an aggregate in order to mutate state of an internal entity instead of passing by the repository of this entity ? Does this mean that in a context of a command, that we do not need of repository for the entity access because aggregate act like that.
@MilanJovanovicTech
@MilanJovanovicTech 5 ай бұрын
Is there a business use case for that? Or is it just CRUD?
@maxencemartin6498
@maxencemartin6498 5 ай бұрын
@@MilanJovanovicTech This is a business use case.
@baranacikgoz
@baranacikgoz 8 ай бұрын
The change you've done to the RemoveExercise method could not be left like that. You did not specified which Include's is used inside GetById method for Workout. If you decide to do that, it is wiser to conditionally include exercises of workouts by specifying exerciseId. Otherwise if there are millions of exercises you are loading all into memory just to remove one.
@MilanJovanovicTech
@MilanJovanovicTech 8 ай бұрын
If there are a large number of exercises, we would implement this differently... But we could also impose a business constraint that a workout can have at most 30 exercises.
@euler.chavez
@euler.chavez 8 ай бұрын
@@MilanJovanovicTech What is this process like, or what would it be like? The "basic" examples are easy to understand, but the complex cases and their variations are rarely explained. For example, in a context where the Family is the aggregate, with entities such as Members and Addresses: a) If I need to obtain only the members, do I always have to access the aggregate? b) If I want to filter address based on type (house, work, business, etc), do I have to do it through the aggregate?
@ChristofferLund
@ChristofferLund 8 ай бұрын
@@MilanJovanovicTech If you could provide an example of how you could elegantly solve this if the related entity has too many to load all into memory that would be nice. I find that to be one of the bigger challenges when using aggregates. Even just having a list of IDs could be too much at one point i presume
@kaozryan
@kaozryan 7 ай бұрын
@@ChristofferLund I'm curious how to solve this also. I think it will be a domain service.
@shakhriyorakhadov8244
@shakhriyorakhadov8244 7 ай бұрын
awesome
@MilanJovanovicTech
@MilanJovanovicTech 7 ай бұрын
Thanks!
@mahyarazad
@mahyarazad 7 ай бұрын
The hidden gem inside this video could be the IReadOnlyList 🤔😎
@MilanJovanovicTech
@MilanJovanovicTech 7 ай бұрын
Never ran into it?
@swift8995
@swift8995 4 ай бұрын
Awesome content! I have a question, can I store an aggregate root id inside a value object? For example I have a currency and country as aggregates, can I include their ids in the address and money value objects?
@MilanJovanovicTech
@MilanJovanovicTech 4 ай бұрын
Currency isn't really an aggregate, though. I consider it more as a value object.
@swift8995
@swift8995 4 ай бұрын
​@@MilanJovanovicTech But what if I need to store exchange rates periodically? Or better way to get conversion every time from third party API?
Domain-Driven Design: The Last Explanation You'll Ever Need
21:05
Software Developer Diaries
Рет қаралды 23 М.
How To Use Domain-Driven Design In Clean Architecture
30:27
Milan Jovanović
Рет қаралды 116 М.
Sigma Kid Mistake #funny #sigma
00:17
CRAZY GREAPA
Рет қаралды 30 МЛН
IL'HAN - Qalqam | Official Music Video
03:17
Ilhan Ihsanov
Рет қаралды 700 М.
7 Design Patterns EVERY Developer Should Know
23:09
ForrestKnight
Рет қаралды 296 М.
What is a Domain Service in Domain-Driven Design?
12:49
Milan Jovanović
Рет қаралды 23 М.
NO SWAGGER? NO PROBLEM! OpenAPI Made Easy in .NET 9
11:48
Milan Jovanović
Рет қаралды 4,2 М.
Mapping Domain-Driven Design Concepts To The Database With EF Core
18:06
Milan Jovanović
Рет қаралды 57 М.
How To Design Amazing REST APIs
18:57
Amichai Mantinband
Рет қаралды 21 М.
Владимир Хориков - Domain-driven design: Cамое важное
1:13:59
DotNext — конференция для .NET‑разработчиков
Рет қаралды 58 М.
Master the Fluent Builder Design Pattern in C#
15:05
Milan Jovanović
Рет қаралды 30 М.
AI Is Making You An Illiterate Programmer
27:22
ThePrimeTime
Рет қаралды 285 М.
Sigma Kid Mistake #funny #sigma
00:17
CRAZY GREAPA
Рет қаралды 30 МЛН