Domain-Driven Design Without An ORM Using The Snapshot Pattern

  Рет қаралды 14,131

Milan Jovanović

Milan Jovanović

Күн бұрын

Пікірлер: 56
@MilanJovanovicTech
@MilanJovanovicTech 2 жыл бұрын
Want to master Clean Architecture? Go here: bit.ly/3PupkOJ Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt
@florianfanderl6674
@florianfanderl6674 2 жыл бұрын
We do the exact same. Works flawless. I'm pretty sure you did the other stuff right in your codebase, but for other users: if you just have getter and setters, it's probably not a domain model. Your domain model should have behavior (aka functions). If they don't live there, you just built another (crappy) ORM.
@MilanJovanovicTech
@MilanJovanovicTech 2 жыл бұрын
"Another crappy ORM" 😂
@Numinalis
@Numinalis Жыл бұрын
This is the pattern I use because I use Dapper. Except, instead of placing these memento methods inside of your domain entity, you can do even better. Have a private class inside of your repository that extends the domain entity with these methods. Also make the memento class a private class inside of the repository. Now, this logic is fully owned by the persistence layer. For a long time, I used to struggle with domain models leaking details that were necessary for infrastructure, and it really bothered me that I was forced to either do that or use a specific ORM. I finally feel satisfied with the above approach.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Why not just extension methods in the Infra layer? Maintaining private classes is a bit tedious (although I completely understand the idea)
@Numinalis
@Numinalis Жыл бұрын
@MilanJovanovicTech That's a great point. You certainly could do this. I will give it a try! I appreciate all of your videos and explanations, Milan. Thank you so much for making these concepts more widely known.
@steve-wright-uk
@steve-wright-uk 2 жыл бұрын
We use this pattern with Entity Framework. The only difference in our implementation is that the To/From methods live within the Snapshot class, not the Domain model class.
@MilanJovanovicTech
@MilanJovanovicTech 2 жыл бұрын
So your EF entities are flat, and you convert to/from rich domain models?
@steve-wright-uk
@steve-wright-uk 2 жыл бұрын
@@MilanJovanovicTech Correct
@christianlavigne874
@christianlavigne874 2 жыл бұрын
I like this approach! This way the domain does not have to be aware of the snapshot and it can all be encapsulated in the persistence layer.
@slobodanmikaric2180
@slobodanmikaric2180 Жыл бұрын
I have a question, when should we dispatch Domain Events. Ideally we do it right after the save method and now I am wondering if they are left out?
@kostasgkoutis8534
@kostasgkoutis8534 Жыл бұрын
How do you access the getters/setters of the domain model then? Reflection magic or you bundle it all together?
@montanomariano
@montanomariano 2 жыл бұрын
I recently had to do something very similar and yes, it indeed becomes more tedious with large domain models!
@MilanJovanovicTech
@MilanJovanovicTech 2 жыл бұрын
If it works, it works 🤷‍♂️
@zikkrype
@zikkrype Жыл бұрын
I guess it’s time to create series of videos about event sourcing with projections and snapshot. That would be nice
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
I definitely want to tackle that!
@Vityhard
@Vityhard 2 жыл бұрын
As you told, it could become a very complex when you have an entities with a lot of relationships. In my project I’m using JSON columns from latest EF core 7.
@MilanJovanovicTech
@MilanJovanovicTech 2 жыл бұрын
Nice option!
@geraaksenov4688
@geraaksenov4688 Жыл бұрын
The Member model doesn't have any relations, how do you cover these without ORM? As you pointed out, email, name and date are all DB-supported types. What if Member would have e. g. a list of Group as a property, and each Group has list of their Members?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
You cover them manually, sadly...
@thomaswoods1365
@thomaswoods1365 Жыл бұрын
I'm finding the Id assignment in FromSnapshot is not working because of protection levels in the entity base classes. Do protection levels need to be softened to make this work?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Protected is fine
@thomaswoods1365
@thomaswoods1365 Жыл бұрын
​ @MilanJovanovicTech I changed from private to protected in the set accessor and that worked. Thanks for all this great content Milan!
@patrykklimas4398
@patrykklimas4398 2 жыл бұрын
We are using similar pattern but outside of domain - in the Infrastructure. Repository is creating Domain object based on it's constructor. Using your presentation (in the domain) you can create domain object without any validation and you are creatating classes which are not connected with domain (snapshots) in the domain. What do you think about it?
@MilanJovanovicTech
@MilanJovanovicTech 2 жыл бұрын
It all revolves around the same idea 😁
@nebularazer
@nebularazer 2 жыл бұрын
Interesting pattern i already used without knowing the name. In my python project i separated my Domain Entities from my ORM Model by having To/From methods on the ORM Models. I would like to go with plain sql too, but i find it difficult to convert rows including joins (all members with all their addresses) back to some model i can represent as json in my api for example. Also change tracking is not a thing with this approach...if i only update the FirstName of a member in your example the database request will still set all 3 properties, right? I would like to see another video with a more complex Domain Entity / Aggregate Root.
@MilanJovanovicTech
@MilanJovanovicTech 2 жыл бұрын
ChangeTracking is definitely not a thing without an ORM, or at least it's not easy to implement. For mapping complex types, Dapper solves it really well by allowing you to map the response into multiple types. I'll show an example of that, you gave me a good idea for a video.
@ramytawfik9168
@ramytawfik9168 Жыл бұрын
something i do not understand please milan Do you mean that we can use mapping library to handle the necessary conversions between our Rich Domain Model and Simple Dto and removing the snapshot pattern?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
You could, yeah
@ramytawfik9168
@ramytawfik9168 Жыл бұрын
@@MilanJovanovicTech Thanks very much
@num1nex337
@num1nex337 2 жыл бұрын
When you inject IDbConnection into your repository, how do you handle disposing the dbconnection after the query is done ? Is it something that's handled behind the scenes ?
@MilanJovanovicTech
@MilanJovanovicTech 2 жыл бұрын
Yes, the context is scoped to the request, so it will be disposed of after it completes
@iliyan-kulishev
@iliyan-kulishev 2 жыл бұрын
The best approach might be to have some kind of IDbConnectionFactory and in the the persisting/quering method create the IDbConnection and wrap the Dapper calls in a using statement.
@davittonoyan6537
@davittonoyan6537 Жыл бұрын
Don't you need to dispose the DbConnection or it is done by Dipendency injection?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Taken care of by DI
@DimonSmart
@DimonSmart Жыл бұрын
Thankyou Milan! You always make a great video! I'd love to know about more complex object with a collection of sub-objects inside. It looks like a problem to save such objects in efficient way. As far as I understand we have to manually implement kind of ORM change tracking. And it looks a bit complicated. Or we have to query whole domain object again and do some tricky manipulations to know if we have some parts inserted, updated or deleted. While googling this approach I found the idea to have a dictionary with DomainObject -> Snapshot (or ORM with change tracking object) object. Looks like this could help but I' not sure.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
You'd pretty much be implementing an IdentityMap which is what EF's ChangeTracker does for you anyhow. I wouldn't bother with implementing that on my own, as there are too many edge cases.
@DimonSmart
@DimonSmart Жыл бұрын
As I understand the Snapshot Pattern could be used for domainmodel and datamodel separation only for simple one table cases?
@christianlavigne874
@christianlavigne874 2 жыл бұрын
How would you go about re-hydrating more complex domain object with children?
@MilanJovanovicTech
@MilanJovanovicTech 2 жыл бұрын
Load them all using a JOIN in the database, or send multiple SQL queries, and then map that into a domain model. This would include multiple snapshot classes also, on for each domain object.
@antonmartyniuk
@antonmartyniuk Жыл бұрын
I like using this approach even when I have a EF Core. That way my DTOs are DDD entities and models being used in Repositories are simple and stupid Dbos. That way my mapping is simple and straightforward and I don't have any overhead of model transformations on the persistent layer. P.S.: DTO naming is relatively speaking, the models returned by WebApi is also stupid and mapped from DDD entities
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
What's the benefit with EF Core however?
@antonmartyniuk
@antonmartyniuk Жыл бұрын
@@MilanJovanovicTech that way DDD level is only on Service/CQRS level. And if you decide to use or not use DDD in the service that way you don't have to rewrite the whole application. Based on the complexity of the service layer you can build it the way you want and other layers might not know about DDD and don't have to know about it
@adisilagy
@adisilagy 2 жыл бұрын
Hi Millan, Two questions: 1. How would you deal with returning a List of members. 2. Would you recommend simply applying an SQL mapper to the value objects so then you want need snapshot entity
@MilanJovanovicTech
@MilanJovanovicTech 2 жыл бұрын
1. Return a list of snapshots, and convert them 2. One option. But it's the same. You just moved the mapping somewhere else.
@jacobjacob8062
@jacobjacob8062 2 жыл бұрын
Where do I find your repository Gatherly?
@MilanJovanovicTech
@MilanJovanovicTech 2 жыл бұрын
I share it on my Patreon: www.patreon.com/milanjovanovic
@ezecel9
@ezecel9 2 жыл бұрын
Hello, are you going to upload your recent conference about modular monoliths? Thanks!
@MilanJovanovicTech
@MilanJovanovicTech 2 жыл бұрын
Yes, I'll post here when it's uploaded (on company's YT channel though)
@wboumans
@wboumans 2 жыл бұрын
Can't you use EF Value Converters?
@MilanJovanovicTech
@MilanJovanovicTech 2 жыл бұрын
The point is not using an ORM
@steve-wright-uk
@steve-wright-uk Жыл бұрын
Via the domain model constructor
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
@KangasniemiJerri
@KangasniemiJerri 2 ай бұрын
"without an ORM" - I mean... Dapper is an ORM?
@MilanJovanovicTech
@MilanJovanovicTech 2 ай бұрын
Object mapper... Where you do all the work. Not a fully-fledged ORM
What Is A Message Queue + RabbitMQ and MassTransit Integration
15:15
Milan Jovanović
Рет қаралды 34 М.
Mapping Domain-Driven Design Concepts To The Database With EF Core
18:06
Milan Jovanović
Рет қаралды 56 М.
Quando eu quero Sushi (sem desperdiçar) 🍣
00:26
Los Wagners
Рет қаралды 15 МЛН
coco在求救? #小丑 #天使 #shorts
00:29
好人小丑
Рет қаралды 120 МЛН
Правильный подход к детям
00:18
Beatrise
Рет қаралды 11 МЛН
Domain Modeling with Domain-Driven Design (From Scratch)
18:05
Milan Jovanović
Рет қаралды 27 М.
Is an ANEMIC Domain Model really that BAD?
10:36
CodeOpinion
Рет қаралды 18 М.
Modeling a Domain With Domain-Driven Design From Scratch | DDD
19:10
Milan Jovanović
Рет қаралды 96 М.
How To Use Domain-Driven Design In Clean Architecture
30:27
Milan Jovanović
Рет қаралды 115 М.
CQRS Doesn't Have To Be Complicated | Clean Architecture, .NET 6
24:09
Milan Jovanović
Рет қаралды 119 М.
Mastering DDD Aggregate Modeling With THESE 3 Steps
17:26
Codewrinkles
Рет қаралды 12 М.
Domain Modeling Gone Wrong - Part 2
10:32
CodeOpinion
Рет қаралды 15 М.
How To Create Smart Enums in C# With Rich Behavior
17:31
Milan Jovanović
Рет қаралды 57 М.
КОРОЧЕ ГОВОРЯ, НЕДЕЛЯ БЕЗ ТЕЛЕФОНА
3:54
LOVE or MONEY? ❤️💸 (PART 14)
0:47
Alan Chikin Chow
Рет қаралды 3,5 МЛН
ТИПЫ ЛЮДЕЙ и зарядка на телефоне🔋
0:32
ЙУЛЯ ПУЛЯ
Рет қаралды 608 М.
Robot 🤖 cleaning 🧹
0:57
Bunnal 𝚃𝚎𝚌𝚑
Рет қаралды 4,7 МЛН