Get the source code for this video for FREE → the-dotnet-weekly.ck.page/entity Want to master Clean Architecture? Go here: bit.ly/3PupkOJ Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt
I'm glad i found your channel. I hate all these "beginner" or standard videos where they always show code that would never be in production but this is some quality stuff thanks 💯
This is kind of the gap that I also noticed, and one I'm trying to fill. By the end of this series we will have created a nice production ready application 😁
@@MilanJovanovicTech thanks for the great work seeing forward to the end and the stuff that comes after that😃 im currently building a production ready system for our startup but im just learning by doing and if you don't find good articles or videos to learn the good stuff you have a big problem
@@MilanJovanovicTech at the moment im building the complete auth server with all the user functionalities, refresh tokens etc. But after that service i want to implement all other functions with microservices for our system because its modern and will later be way easier to do maintenance. And it would be nice to find something in depth about microservices like the complete implementation with docker/kubernetes and the code itself and the api gateways and maybe backend communication like rabbit mq
@@MilanJovanovicTech Can you add implementing auth functionality along with refresh token in your future videos along with concepts like mapping the data from jwt token to profile class and then using that class inside other endpoints.
you've got a great way of explaining things. I'm by no means a beginner anymore but your videos are always a great refresher, I really appreciate your effort with these
I love the simplicity of following YAGNI principle for your example. Many books and examples throw you a lot of boilerplate code that may not be necessary when learning DDD techniques. Thanks for sharing.
Have to admit this CA&DDD series is fantastic! Very well explained step by step with logical explanation and why something is a good practice. I started to like DDD just by watching your videos. Thank you Milan! 👏💪
I am very happy to find this channel and the explanations are clear and precise and I look forward to the next videos. A big thank-you. Just a question M Milab: How do you choose the naming of the folders and what they should contain, for example the primitive folder?
Hi, and welcome to the channel! 😁 Copying the answer from another thread: So using "Abstractions" and "Primitives" for these kinds of common/base types is something I picked up from Microsoft. If you notice how they create their namespaces, interfaces and types are usually defined in a namespace ending with either ".Abstractions" or ".Primitives"
Great video, a small heads-up nevertheless: Using Guids directly for ids may be considered as a primitive type obsession... You're setting the fundamentals and you didn't talk about value objects yet, but I think this should be mentioned because It will affect your base Entity implémentation. I think PTO is a key concept if we're doing DDD soo that's just my thoughts.
That's a great observation. I'm covering ValueObjects in one of the future videos, and also talking about Primitive Obsession. However, I didn't touch on strongly typed Ids. I'm thinking of making a separate video on that topic, now that you mentioned it.
If we go down the "Primitive type obession" rabit hole you wont even have strings and int in the entities :) Or is it anything specific for GUID's that I'm missing
@@tiagocandeias3969 I was mainly referring to strongly type IDs. We don't apply PTO on every property, the FirstName for example can stay a string but if you were to add an address then it might be better as a value object. Applying it everywhere would be insane;)!
I think the line is kind of blurry between them. I prefer not applying the AggregateRoot pattern, as I tend to end up with big aggregates with a lot of logic. Also, just because the pattern exists doesn't mean you have to use it. 😁
That's a great question. So using "Abstractions" and "Primitives" for these kinds of common/base types is something I picked up from Microsoft. If you notice how they create their namespaces, interfaces and types are usually defined in a namespace ending with either ".Abstractions" or ".Primitives"
Will you be covering Aggregates? It seems even with this simple domain, if for example a Gathering was to be canceled this would effect other Entities/Value Objects.
I'm still uncertain about that one Paul. Not sure if I just want to continue with Domain Events, or tackle it from an Aggregate perspective. Going to decide this weekend anyway 😁
Hi Milan, really great information here! Just one question when you implement the Equal(Entity? other) method. Since you already have the Equal(object? obj) method, can't you utilize this when you create the Equal(Entity? other) as well? Something like this " public bool Equals(Entity? other) { return Equals(other); }". I want to know if this is the same or I am missing something. Thank again for your work!
Nice tutorial! On the other hand I would add more details information about what's difference between Anemic Domain Model and Rich Domain Model approaches. In which case we need to pick the Anemic Domain Model or Rich Domain Model ?
Hello, Milan, You made your Gathering class as sealed. My sonarsource tells me of a bad smell RSPEC-4035 Tells me - Classes implementing "IEquatable" should be sealed Is it okay if I remove sealed because I need to have inheritance? And I also don't get if a "domain layer" can have an interface folder for interfaces for entities. Example: I've got hierarchy: BaseMaterial -> Material, PackMaterial and all of them implement IMaterial interface in which I guarantee that all classes that implement it have some fields and some methods I expect them to have.
Great content and didactic Milan, congrats! Could I suggest a Builder creational pattern in case of complex Entity. Next video will be Object Value :) ? Best regards
Really great video. My only concern is the use of Guid's. I work in the online gaming industry and we have an extremely high transaction rate, thousands of bets a minute. Guids have not fared very well and we have been actively removing them for smaller data types. Not sure how we would apply this, with say a INT or Short data type.
This is cool and very helpful, however, I haven't found an explanation in any of your videos on how to perform entity validation that require any interaction with DB (e.g. duplicate user name). Naturally, this type of validation should be encapsulated in an entity but, of course, you won't inject a repository into an entity to check duplicates.
@@MilanJovanovicTech as long as we stick to the previously defined standard, it is fine. I found many times people are doing validation that involves DB calls in DomainService class which leads us to an anemic domain model (entity), though sometimes. Btw, can you point to the video where you explained CreateMemberCommandHandler and Domain Services?
Hi Milan. Why not let the base Entity instantiate the Id in the ctor or the prop. What's the benefit of passing it via ctor parameter only to use .NewId in every case?
You are going to get some funny behavior if you use EF as your ORM. EF calls the constructor that it deems appropriate when materializing entities. So that ctor that sets the Id may get called on every read from the DB, so you will end up with a random Id on each try. Be careful with that one.
Hi Koro, you can do this, but you have to make the set of the Id property public, so ef core will overwrite the instantiated Id whe materializing entities. Maybe you can try to have two constsructors, one for creating new entities, and the other one for existing entities and test how EF is handling this.
I started watching your videos all the way from the oldest. I really like what DDD brings, but can't we avoid having ids as Guids ? Can't I just rely on DBMS and the autoincrement mechanism there ?
It becomes quite a bit verbose, honestly. Entity has to be generic, and you need to solve strongly typed ID equality as a generic argument. Amichai had an interesting take in a recent video
@@MilanJovanovicTechI'm not completely sure, but I think that GetType comparison guarantees that they're the same type. And the second if statement is not really needed, you could just type cast the object to the entity like this: Entity entity = (Entity)obj
41 is a prime number. When multiplying with a prime number you are more likely to produce an even distribution of hash codes across hash buckets. Resulting in less hash colisions.
Can we make an entity that has a generic type rather than Guid? Because some entities may have primary keys as integer, some may have bigint, some may have Guid etc.. if yes, then how. Thanks!
Thanks for the video got a question whats the harm in putting interface over these entities. Other than multiple possible implementations. Because entities take out the testability can't really substitute or mock one of these for testing. How would you test when entity grow it becomes painful
@@MilanJovanovicTech Example I have OrderProcessHandler which takes an orderRecoverRequest. Now behaviour of the handler is. it should first load order then it should run order through a rule engine if order is valid then it should update status and send then email. Now without interface over entity you would have to create the entity in valid state run the rules engine that will raise all events and then only you can check email sent or not. So that valid state arrange is hard to setup. In interface over entity scenario I would just AutoData ask the mock factory to give me an intance and mock the other events which states that rules passed then check sendEmail is called.
Also, why do you use an "Entity?" This is a class, so it can be null anyway? Or it for other developers? Your VS doesn't recommend you remove "?" because this isn't a value object?
You create 2 Equals. why not Equals( obj ) => Equals( obj as Entity )? No code duplicates. You check GetType == GetType and obj is Entity. @this is child of Entity. obj has equal type. so obj is Entity. So half of your code is garbage. ==: if first is null and second is null => null == null => true. but your code returns false. 1 small class full of thrash. Good job boy.
im from iran and i cant pay $ for you from iran . how to access the code . I realy watch full of your video. andnow inee then code but I canr pay for this because im from iran what should I do?
Get the source code for this video for FREE → the-dotnet-weekly.ck.page/entity
Want to master Clean Architecture? Go here: bit.ly/3PupkOJ
Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt
I'm glad i found your channel. I hate all these "beginner" or standard videos where they always show code that would never be in production but this is some quality stuff thanks 💯
This is kind of the gap that I also noticed, and one I'm trying to fill. By the end of this series we will have created a nice production ready application 😁
@@MilanJovanovicTech thanks for the great work seeing forward to the end and the stuff that comes after that😃 im currently building a production ready system for our startup but im just learning by doing and if you don't find good articles or videos to learn the good stuff you have a big problem
@@flobuilds Anything that would benefit you in particular?
@@MilanJovanovicTech at the moment im building the complete auth server with all the user functionalities, refresh tokens etc. But after that service i want to implement all other functions with microservices for our system because its modern and will later be way easier to do maintenance. And it would be nice to find something in depth about microservices like the complete implementation with docker/kubernetes and the code itself and the api gateways and maybe backend communication like rabbit mq
@@MilanJovanovicTech Can you add implementing auth functionality along with refresh token in your future videos along with concepts like mapping the data from jwt token to profile class and then using that class inside other endpoints.
Your monolog with these is excellent and demonstrates a masterful command of both English and the rest of this stuff.
Thanks a lot :)
you've got a great way of explaining things. I'm by no means a beginner anymore but your videos are always a great refresher, I really appreciate your effort with these
I appreciate that Chris, thank you!
I love the simplicity of following YAGNI principle for your example. Many books and examples throw you a lot of boilerplate code that may not be necessary when learning DDD techniques. Thanks for sharing.
I had to follow those many book and examples to be able to explain it simple like this 😅
Hopefully this speeds up others learning about DDD
Have to admit this CA&DDD series is fantastic! Very well explained step by step with logical explanation and why something is a good practice. I started to like DDD just by watching your videos. Thank you Milan! 👏💪
Glad you enjoyed it!
Nice video, Milan. Your videos are awesome because you keep it simple and go over from basic to advance concepts. Love this format. Keep it up!!!
Thank you, I'm really glad you are liking the channel so far. More great videos are coming 😊
Awesome Milan! I see you on Twitter often but not TH-cam
Hopefully the algo starts showing me some love 😁
I am very happy to find this channel and the explanations are clear and precise and I look forward to the next videos.
A big thank-you.
Just a question M Milab: How do you choose the naming of the folders and what they should contain, for example the primitive folder?
Hi, and welcome to the channel! 😁
Copying the answer from another thread:
So using "Abstractions" and "Primitives" for these kinds of common/base types is something I picked up from Microsoft. If you notice how they create their namespaces, interfaces and types are usually defined in a namespace ending with either ".Abstractions" or ".Primitives"
Yu are right! He's keep to explain what he's writes..
You cheeky boy putting this out today rather than tomorrow. 😉Great job Milan!
But I am aiming for Tuesday-Thursday anyhow 🤷♂️
😊😊
3:10 This might be late, but as long as you only initialize it in the constructor you don't even need a setter. `public Guid Id { get; }` is enough.
True
Great video, a small heads-up nevertheless:
Using Guids directly for ids may be considered as a primitive type obsession... You're setting the fundamentals and you didn't talk about value objects yet, but I think this should be mentioned because It will affect your base Entity implémentation.
I think PTO is a key concept if we're doing DDD soo that's just my thoughts.
That's a great observation. I'm covering ValueObjects in one of the future videos, and also talking about Primitive Obsession. However, I didn't touch on strongly typed Ids. I'm thinking of making a separate video on that topic, now that you mentioned it.
If we go down the "Primitive type obession" rabit hole you wont even have strings and int in the entities :) Or is it anything specific for GUID's that I'm missing
@@tiagocandeias3969 I was mainly referring to strongly type IDs. We don't apply PTO on every property, the FirstName for example can stay a string but if you were to add an address then it might be better as a value object.
Applying it everywhere would be insane;)!
Totally agree, as I’d make my Id a ValueObject as well.
Awesome! Keep 'em coming. I see people using like an aggregate root to define the entity id
I think the line is kind of blurry between them. I prefer not applying the AggregateRoot pattern, as I tend to end up with big aggregates with a lot of logic.
Also, just because the pattern exists doesn't mean you have to use it. 😁
@@MilanJovanovicTech thanks alot 🙏, I appreciate, its much more clearer now
I hope to be like you one day. Thanks for being an inspiration
You can do it!
Good work! MIlan, Continue please! However, I have a question. What is your thought process behind naming the folder 'Primitives'?
That's a great question. So using "Abstractions" and "Primitives" for these kinds of common/base types is something I picked up from Microsoft. If you notice how they create their namespaces, interfaces and types are usually defined in a namespace ending with either ".Abstractions" or ".Primitives"
@@MilanJovanovicTech Good spot!
Will you be covering Aggregates? It seems even with this simple domain, if for example a Gathering was to be canceled this would effect other Entities/Value Objects.
I'm still uncertain about that one Paul. Not sure if I just want to continue with Domain Events, or tackle it from an Aggregate perspective. Going to decide this weekend anyway 😁
@@MilanJovanovicTech I understand. Is there a reason you did not make the Id property of your Entity class a Value Object?
@@paulbarton2280 Guid is a struct which already has the behavior the Value Object pattern would give.
Hi Milan, really great information here! Just one question when you implement the Equal(Entity? other) method. Since you already have the Equal(object? obj) method, can't you utilize this when you create the Equal(Entity? other) as well? Something like this " public bool Equals(Entity? other)
{
return Equals(other);
}". I want to know if this is the same or I am missing something. Thank again for your work!
You'd have to cast it to an object, so that's one downside, otherwise it's possible
Your videos are so informative, thank you!
You are so welcome!
Братан, хорош, давай, давай, вперёд! Контент в кайф, можно ещё? Вообще красавчик! Можно вот этого вот почаще?
More about DDD or more about Entities?
extreme code
Nice tutorial! On the other hand I would add more details information about what's difference between Anemic Domain Model and Rich Domain Model approaches. In which case we need to pick the Anemic Domain Model or Rich Domain Model ?
I made a separate video on that
@@MilanJovanovicTech Awesome! 😎
Hello, Milan,
You made your Gathering class as sealed. My sonarsource tells me of a bad smell RSPEC-4035 Tells me - Classes implementing "IEquatable" should be sealed
Is it okay if I remove sealed because I need to have inheritance?
And I also don't get if a "domain layer" can have an interface folder for interfaces for entities. Example: I've got hierarchy: BaseMaterial -> Material, PackMaterial and all of them implement IMaterial interface in which I guarantee that all classes that implement it have some fields and some methods I expect them to have.
If you need inheritance, of course
@@MilanJovanovicTech thx! 👍
Great content and didactic Milan, congrats!
Could I suggest a Builder creational pattern in case of complex Entity.
Next video will be Object Value :) ?
Best regards
Next video will be Domain validation.
Followed by Value Object, Aggregates, Domain Events... 😁
Really great video. My only concern is the use of Guid's. I work in the online gaming industry and we have an extremely high transaction rate, thousands of bets a minute. Guids have not fared very well and we have been actively removing them for smaller data types. Not sure how we would apply this, with say a INT or Short data type.
You probably don't generate those values client-side?
Hi Milan, what is the logic by multiplying the GetHasCode method by a prime number?
Provides a more even distribution of the hash code, nothing fancy though
Good stuff! Why you have 2x Equals methods in the Entity class? isn't the one on the Entity (Equatable interface) enough?
One is object.Equals and one is IEquatable.Equals
Why do We have to check equality between two objects in DDD, Thanks for video and please keep posting videos
How else would we know if two entities are the same?
This is cool and very helpful, however, I haven't found an explanation in any of your videos on how to perform entity validation that require any interaction with DB (e.g. duplicate user name). Naturally, this type of validation should be encapsulated in an entity but, of course, you won't inject a repository into an entity to check duplicates.
There's a video on user registration and validating duplicate emails that I'm sure you'll enjoy
4 Ways To Do Email Uniqueness Check, let me know what you think after watching
@@MilanJovanovicTech as long as we stick to the previously defined standard, it is fine. I found many times people are doing validation that involves DB calls in DomainService class which leads us to an anemic domain model (entity), though sometimes. Btw, can you point to the video where you explained CreateMemberCommandHandler and Domain Services?
@@vertikalniserklaz8694 th-cam.com/video/eC7GMGIR4Gw/w-d-xo.html
A question. Why would you need to compare entities in your domain: collision or what? Who would need to use equality on these ?
Semantics
Hi Milan. Why not let the base Entity instantiate the Id in the ctor or the prop. What's the benefit of passing it via ctor parameter only to use .NewId in every case?
You are going to get some funny behavior if you use EF as your ORM. EF calls the constructor that it deems appropriate when materializing entities. So that ctor that sets the Id may get called on every read from the DB, so you will end up with a random Id on each try. Be careful with that one.
Hi Koro, you can do this, but you have to make the set of the Id property public, so ef core will overwrite the instantiated Id whe materializing entities. Maybe you can try to have two constsructors, one for creating new entities, and the other one for existing entities and test how EF is handling this.
I started watching your videos all the way from the oldest. I really like what DDD brings, but can't we avoid having ids as Guids ? Can't I just rely on DBMS and the autoincrement mechanism there ?
Absolutely, there's no reason you can't go with that. This was just a design decision at the time
thanks
You're welcome!
Is there going to be more refactoring so that we can execute moq frameworks to unit test?
I will tackle testing at some point for sure.
@@MilanJovanovicTech thanks Milan
Does EF Supports init modifier?
Yes
very good video
Thanks!
How would this approach change if you are using strongly typed IDs for your entities. Would you still need this base Entity functionality?
It becomes quite a bit verbose, honestly. Entity has to be generic, and you need to solve strongly typed ID equality as a generic argument. Amichai had an interesting take in a recent video
If all my entities use different data types for their ID, is it acceptable to convert the Entity class to a generic type?
You can - but beware of how you will use that Entity in any generic context
Aren't the if statements when you compare obj.GetType() and that object is an Entity check the same thing?
What guarantees that they are the same type?
@@MilanJovanovicTechI'm not completely sure, but I think that GetType comparison guarantees that they're the same type. And the second if statement is not really needed, you could just type cast the object to the entity like this:
Entity entity = (Entity)obj
Why do you need init in Entity class? Because we set ID using constructor anyway, we just need readonly ID property, don't we?
Make it easier when materializing entity
Awesome!
Should I do more DDD content? 😁
Nice video. Why 41?
41 is a prime number.
When multiplying with a prime number you are more likely to produce an even distribution of hash codes across hash buckets. Resulting in less hash colisions.
@@MilanJovanovicTech Thank you Milan. :)
@@MilanJovanovicTech I think that we need to extract this magic number 41. Create a const variable and describe it. What do you say?
Can we make an entity that has a generic type rather than Guid? Because some entities may have primary keys as integer, some may have bigint, some may have Guid etc.. if yes, then how. Thanks!
Of course, just more boilerplate
@@MilanJovanovicTechcan you post something on this as community post?
@@microtech2448 Sure 😁
@@MilanJovanovicTech thanks 🙂
1:03 - Definition* of Entity
Indeed
Thanks for the video got a question whats the harm in putting interface over these entities. Other than multiple possible implementations. Because entities take out the testability can't really substitute or mock one of these for testing. How would you test when entity grow it becomes painful
Why would you ever want to mock an entity?
@@MilanJovanovicTech
Example I have OrderProcessHandler which takes an orderRecoverRequest. Now behaviour of the handler is.
it should first load order then it should run order through a rule engine if order is valid then it should update status and send then email. Now without interface over entity you would have to create the entity in valid state run the rules engine that will raise all events and then only you can check email sent or not. So that valid state arrange is hard to setup.
In interface over entity scenario I would just AutoData ask the mock factory to give me an intance and mock the other events which states that rules passed then check sendEmail is called.
@@MilanJovanovicTech also that enables whether entity method has been called from handler testing. Appreciate your input on this
Also, why do you use an "Entity?" This is a class, so it can be null anyway? Or it for other developers? Your VS doesn't recommend you remove "?" because this isn't a value object?
Just making things explicit
@@MilanJovanovicTechThank you very much for answering)
Entities vs aggregates in a phrase.
Which is cooler?
You create 2 Equals. why not Equals( obj ) => Equals( obj as Entity )? No code duplicates. You check GetType == GetType and obj is Entity. @this is child of Entity. obj has equal type. so obj is Entity. So half of your code is garbage. ==: if first is null and second is null => null == null => true. but your code returns false. 1 small class full of thrash. Good job boy.
Thanks!
im from iran and i cant pay $ for you from iran . how to access the code . I realy watch full of your video. andnow inee then code but I canr pay for this because im from iran what should I do?
I'm not sure what we can do in that case. I think Patreon should support local currencies also, as long as you have a valid bank card.
use light screen your tool in black mode and video is not clear
Thanks
Try to focus more on concept rather than code
Dry
Why?????
Hi, do you want to be a programmer? I will make it as hard as possible for you okay? Why? I don't know, that's just the way I am.
How would you solve this? 😁