Want to master Clean Architecture? Go here: bit.ly/3PupkOJ Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt
@silverfox3074
Ай бұрын
Excellent video! But I was thinking if there is any way that filter by isDeleted to be automatically? For example not to check every record if isDeleted but method where to handle this automatically?
@Isr5d
2 ай бұрын
Soft delete is a great feature if you want to add 2-step deletion process to the user. User can recover the deleted items within a respected period of time, or can delete them permanently. In case the time of deletion has reached the recovery time threshold, the system will delete them permanently. It's like user recycle bin. You can adapt hierarchy approval to it as well. So user will soft delete the entry, but a supervisor can either approve deletion process or reject it.
@ajdinhusic2574
2 ай бұрын
There is additional reasons to use soft deletes. Sometimes you need to retain related data, like calculations, results, statistics, reports etc.. Often times you dont want to destroy those just because a record was deleted
@MilanJovanovicTech
2 ай бұрын
That's a very nice use case
@user-kh8mv2be8t
26 күн бұрын
It is better to do this kind of thing using the SavingChanges delegate rather than overriding the SaveChangesAsync. There are multiple SaveChangesAsync overloads which internally call SaveChangesAsync(bool, CancellationToken), so you'd need to make sure you are overriding the correct one or else your logic will get skipped if a different signature is invoked, this also doesn't cover non-async calls using the SaveChanges() method, so you'd need to cover that set as well to implement this properly, finally the dispose check code runs just before that delegate is invoked, which will give you a nicer and more consistent error message if someone tried to invoke the method on a disposed instance. This also allows you to either include it in the class as you do here or attach the logic as needed.
@MilanJovanovicTech
26 күн бұрын
I only ever call SaveChangesAsync from my code, but that's a valid concern. We could move this logic into an interceptor, though.
@Kingside88
Ай бұрын
Thank you, Milan. An incredibly good explanation.
@MilanJovanovicTech
Ай бұрын
Glad you enjoyed it!
@kewqie
2 ай бұрын
At 4:15, why not just do "product.IsDeleted = true;" before calling "Update(product)" instead of doing that long ".Property()" call after?
@ajdinhusic2574
2 ай бұрын
product.IsDeleted = true marks the EntityState as Updated, and so an Update Event is fired instead of a Delete event.
@kewqie
2 ай бұрын
@@ajdinhusic2574 isn't that done by the Update()? He talks about it 15s earlier.
@MilanJovanovicTech
2 ай бұрын
1) IsDeleted had a private set 2) Yeah, Update isn't necessary there. But just wanted to make it explicit since I had Remove() beforehand.
@PurpleDaemon_
Ай бұрын
10:12 a filtered index on a bool fields one only makes sense in the opposite case, when you are filtering a much smaller part. In your case, your index will cut off a couple of percent at most and will most likely be completely ignored by the base. And here are two additional things to think about when implementing a soft-delete: 1) Without additional changes hidden objects will still be taken into account when checking the uniqueness of fields by the database 2) Soft-deliting an object with cascading dependencies can lead to an invalid state of the database.
@MilanJovanovicTech
Ай бұрын
1) That's a nice problem to consider. But I'd look at it as a business decision and see what makes sense. Maybe we can make due without a unique check, and do a query at runtime. 2) How so? As in, the dependents wouldn't be marked as deleted?
@PurpleDaemon_
Ай бұрын
@@MilanJovanovicTech 2 - yep, you could have items with soft-deleted parent, which can easily break FE or other stuff.
Ай бұрын
I think in terms of ddd and clean architecture it would be better to use a shadow property in the EF configuration instead of modifying the domain layer
@MilanJovanovicTech
Ай бұрын
That might make sense, yeah
@kjbetz
2 ай бұрын
Excellent video as always Milan!
@MilanJovanovicTech
2 ай бұрын
Thanks a lot!
@saleem.shaikh
2 ай бұрын
Next video, if you can, please do a video on audit trail, and how to implement it, can we use mediatr for it or not.
@MilanJovanovicTech
2 ай бұрын
I discussed how to do this with EF Core: kzitem.info/news/bejne/zneitWeFrqGCqaQ
@ajdinhusic2574
2 ай бұрын
I feel like there must be a library by now for soft-deletes using EF core, right? Also Milan, what do you say about implementing ISoftDeletable using a nullable DateTime(Offset) type for the deletion marking. as this contains more information that might be useful. The filter and index would then be on: DeletedAt == null .
@MilanJovanovicTech
2 ай бұрын
I believe I mentioned that we could use a DateTime column 🤔 Fine by me.
@ajdinhusic2574
2 ай бұрын
@@MilanJovanovicTech yeah but I thought you meant as an additional column alongside the boolean? Or instead of the boolean? If its instead of the boolean then yes thats what I meant. Which do you prefer btw?
@andyhb1970
2 ай бұрын
I find soft deletes to be invaluable, firstly it enables easier tracking of deletes for migrating changes via ETL processes to external systems and secondly users can't be trusted and soft deletes have saved many a painful situation over the years 🎉
@MilanJovanovicTech
2 ай бұрын
Let's go soft deletes! 😁
@saleem.shaikh
2 ай бұрын
Nice video.
@MilanJovanovicTech
2 ай бұрын
Thanks a llot!
@daniel_klement_photography
Ай бұрын
More this simple and useful videos!
@MilanJovanovicTech
Ай бұрын
Will do :)
@user-ko2yo3zx8h
2 ай бұрын
Thanks 👍
@MilanJovanovicTech
2 ай бұрын
Any time!
@ChrisWard74
2 ай бұрын
I'm new to EF Core so I have lots to learn. When you added IsDeleted you had a Migrate function do you have more details on what that is/does? Do you write that function and it's run one time to modify the database?
@MilanJovanovicTech
Ай бұрын
It's an extension method that applies EF Core migrations when the application starts. dbContext.Database.Migrate();
@ChrisWard74
Ай бұрын
@@MilanJovanovicTech Wouldn't it be better to do these migrations outside of code in a SQL script? Over time you could have more and more migrations as things change so you wouldn't want all of those migrations running every time or checking to see if they need to run every time the application is started.
@yotelolailo
19 күн бұрын
@@ChrisWard74 They are run only in development environments. Usually for production environments you have to select a different technique to run your migrations manually or automated but not on every application start.
@AlejandroPerez-m9r
2 ай бұрын
Could you please tell me which visual theme you use, or could you share the colors you use in your configuration, or make a video about it? Thank you very much.
@MilanJovanovicTech
2 ай бұрын
ReSharper
@AlejandroPerez-m9r
Ай бұрын
@@MilanJovanovicTech Would you be so kind as to indicate how to achieve that configuration, please?
@romualdhenry1633
2 ай бұрын
Hi Milan thank you for all of your videos ! I have a question about Clean Architecture, I would to do some Business Calculations (like calculate prices), and I would like to know in what layer I should do and in what class Thank you so much ❤
@MilanJovanovicTech
2 ай бұрын
Probably Application, but hard to tell without context
@ajdinhusic2574
2 ай бұрын
@@MilanJovanovicTech exactly. First that comes to mind is application, but like you said, it depends. For example, many calculations can often times be attributed to the domain layer. Its often worth to think about it more closely.
@arteqppp6223
Ай бұрын
Any reason not to do some base AuditableEntity class, which would have IsDeleted, DeletedOnUtc, Id, itd for all of entites?
@MilanJovanovicTech
Ай бұрын
I'm just giving ideas here, you can take it further with something like that 😁
@arteqppp6223
Ай бұрын
@@MilanJovanovicTech Sure, thanks!
@matthewrossee
2 ай бұрын
Hi Milan! How would you implement cross-cutting concerns like validation or caching WITHOUT using MediatR and its pipelines? Let's say the classical service architecture. Maybe one could use a decorator pattern with Scrutor. Do you know how to implement something like this?
@MilanJovanovicTech
2 ай бұрын
Middleware? 🤔
@matthewrossee
2 ай бұрын
@@MilanJovanovicTech I guess it’s an option but seems a bit clunky. Can’t find a good repo that demonstrates something different than mediatr pipelines
@MilanJovanovicTech
2 ай бұрын
@@matthewrossee Which is why MediatR is so awesome. I never understood the hate against, considering how many awesome options it unlocks.
@matthewrossee
2 ай бұрын
@@MilanJovanovicTech have you used the Martin Othamar’s mediator implementation? The same API, but uses source generated code, maybe you’ll find this interesting.
@saddamhossaindotnet
2 ай бұрын
Excellent content!
@MilanJovanovicTech
2 ай бұрын
Much appreciated!
@alexxx8338
Ай бұрын
Found problems imlementing this on my aggregate with nested soft delete entities collections in it. Quer filters are not going to solve my problems in this case
@MilanJovanovicTech
Ай бұрын
True. Collections make this quite a bit harder.
@haroldpepete
2 ай бұрын
great video, i implemented sofdelete in one project, but some questions come to my mind, what happen if i mark a isdeleted flag in one record, a producct record for taking an example, when i try to register another product with the same name like my softdelete flag and my database has a unique constraint by name? how i can manage this behavior? because i gonna have problem trying to register a new product with the same name with some product marked as softdelete
@MilanJovanovicTech
2 ай бұрын
That's a business question, not a technical one
@PurpleDaemon_
Ай бұрын
Depending on you DB use nullable bool field or filtered index.
@ibowyer
2 ай бұрын
I have used temporal tables in ef core for archiving data changes before do you think that is another possible solution?
@ajdinhusic2574
2 ай бұрын
Yes, that reminds me of that event sourcing pattern that was recently highlighted by Nick Chapsas
@MilanJovanovicTech
2 ай бұрын
Yes, albeit more complex
@barr5221
2 ай бұрын
what about SQL server temporal table or table with from and until date? Soft deletes + full history of the changes on the table. Very usefull when debugging what happended to your data.
@MilanJovanovicTech
2 ай бұрын
Too complex for this video 😅
@kman12275
2 ай бұрын
I love the temporal tables most of the time. I am considering a soft delete though where the user might bring the record back.
@andyhb1970
2 ай бұрын
SQL Change Data Capture works extremely well and I've used it to feed an ETL process to our data warehouse and it all works perfectly in Azure SQL as well.
@RikinPatel13
2 ай бұрын
How to do same things in CosmosDB with Linq?
@MilanJovanovicTech
2 ай бұрын
No idea
@codenetw
Ай бұрын
How about not creating additional entities in the database and maintaining them by moving items, but instead simply partitioning by the IsDeleted flag? When querying with a filter, the database will more easily select from the partition where IsDeleted = false. create table if not exists products ( ... product text, isDeleted boolean ) PARTITION BY LIST (isDeleted); CREATE TABLE products_new PARTITION OF products FOR VALUES IN (false); CREATE TABLE products_deleted PARTITION OF products FOR VALUES IN (true);
@MilanJovanovicTech
Ай бұрын
I think that's a PostgreSQL feature, right? Would it automatically move records from the products_new to products_deleted partition on update?
@codenetw
Ай бұрын
@@MilanJovanovicTech I thought that mssql also supports this function, but yes, you are right, it will not allow you to update the record if it is a key for the partition :(
Пікірлер: 76