Want to master Clean Architecture? Go here: bit.ly/3PupkOJ Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt
@vantavoids6 ай бұрын
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
@MilanJovanovicTech6 ай бұрын
Glad it was helpful, and no worries I don't have a mic anywhere (or do I?)
@enricoroselino7557Ай бұрын
milan sure have mic everywhere 😂
@sergiom.9546 ай бұрын
The value of your content is unique. Thanks Milan
@MilanJovanovicTech6 ай бұрын
No, thank you! :)
@ferventurart5 ай бұрын
Great Milan, your explain a complex concept in a simple example! 👏
@MilanJovanovicTech5 ай бұрын
Glad you liked it!
@BlindVirtuoso6 ай бұрын
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.
@MilanJovanovicTech6 ай бұрын
Wanted to focus on maintaining a consistency boundary
@davidjiang79295 ай бұрын
Would you happen to have more examples on the unit of work and how to save aggregate to database?
@MilanJovanovicTech5 ай бұрын
Well, I've got a bunch of videos on the channel covering DDD aggregates directly or indirectly
@alexramossilva6 ай бұрын
Can you talk about Business Rule Engines and what are the design patterns appropriate to implement it?
@MilanJovanovicTech6 ай бұрын
Not familiar with them
@Luke_Ainsworth3 ай бұрын
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?
@MilanJovanovicTech3 ай бұрын
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Ай бұрын
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Ай бұрын
I don't know man 😅 This type of modeling question requires much more context than could fit in a YT comment.
@vuhoang5903Ай бұрын
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Ай бұрын
Yes, that is acceptable. Holding references (IDs) to other entities is fine.
@pvlzhАй бұрын
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Ай бұрын
Yes, correct
@MdSayeedRahman-h3e3 ай бұрын
Great content!
@MilanJovanovicTech3 ай бұрын
Thanks a lot :)
@JonathanW-k6cАй бұрын
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Ай бұрын
That would depend on how much information we're storing. If the lists are bounded (finite # of elements), that could be a viable option.
@victorgarcia35266 ай бұрын
Hey Milan, what if you push your code examples to github so we can check the code while watching the video?
@MilanJovanovicTech6 ай бұрын
I share the code on Patreon
@maxencemartin64982 ай бұрын
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.
@MilanJovanovicTech2 ай бұрын
Is there a business use case for that? Or is it just CRUD?
@maxencemartin64982 ай бұрын
@@MilanJovanovicTech This is a business use case.
@thomaswoods13654 ай бұрын
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.
@MilanJovanovicTech4 ай бұрын
What is the "it" that's set to modified?
@thomaswoods13654 ай бұрын
@@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.
@thomaswoods13654 ай бұрын
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.
@thomaswoods13654 ай бұрын
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?
@thomaswoods13654 ай бұрын
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.
@wannadie99506 ай бұрын
awesome job milan, love you
@MilanJovanovicTech6 ай бұрын
Thanks a lot! :)
@mahmoudali16604 ай бұрын
What do you mean by the use case? Thank you
@MilanJovanovicTech4 ай бұрын
A component providing the desired functionality for one feature
@baranacikgoz6 ай бұрын
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.
@MilanJovanovicTech6 ай бұрын
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.chavez6 ай бұрын
@@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?
@ChristofferLund6 ай бұрын
@@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
@kaozryan5 ай бұрын
@@ChristofferLund I'm curious how to solve this also. I think it will be a domain service.
@mahyarazad4 ай бұрын
The hidden gem inside this video could be the IReadOnlyList 🤔😎
@MilanJovanovicTech4 ай бұрын
Never ran into it?
@shakhriyorakhadov82445 ай бұрын
awesome
@MilanJovanovicTech5 ай бұрын
Thanks!
@swift8995Ай бұрын
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Ай бұрын
Currency isn't really an aggregate, though. I consider it more as a value object.
@swift8995Ай бұрын
@@MilanJovanovicTech But what if I need to store exchange rates periodically? Or better way to get conversion every time from third party API?