diff --git a/categories/software-engineering/rules-to-better-sql-databases-developers.mdx b/categories/software-engineering/rules-to-better-sql-databases-developers.mdx index 4c97e908677..47cb816847d 100644 --- a/categories/software-engineering/rules-to-better-sql-databases-developers.mdx +++ b/categories/software-engineering/rules-to-better-sql-databases-developers.mdx @@ -13,7 +13,7 @@ index: - rule: public/uploads/rules/do-not-allow-nulls-in-number-fields-if-it-has-the-same-meaning-as-zero/rule.mdx - rule: public/uploads/rules/avoid-spaces-and-empty-lines-at-the-start-of-character-columns/rule.mdx - rule: public/uploads/rules/use-identities-in-sql-server/rule.mdx -- rule: public/uploads/rules/avoid-deleting-records-by-flagging-them-as-isdeleted/rule.mdx +- rule: public/uploads/rules/retain-deleted-records-with-a-soft-delete/rule.mdx - rule: public/uploads/rules/make-sure-you-have-valid-date-data-in-your-database/rule.mdx - rule: public/uploads/rules/datetime-fields-must-be-converted-to-universal-time/rule.mdx - rule: public/uploads/rules/use-temporal-tables-to-audit-data-changes/rule.mdx @@ -86,4 +86,4 @@ Here are some of the typical things that all SQL Server DBAs and Database develo View [Database Coding Standard and Guideline](http://www.nyx.net/~bwunder/dbChangeControl/standard.htm). -Want to develop your SQL Server Database with SSW? Check [SSW's Databases consulting page](https://www.ssw.com.au/consulting/database-development). \ No newline at end of file +Want to develop your SQL Server Database with SSW? Check [SSW's Databases consulting page](https://www.ssw.com.au/consulting/database-development). diff --git a/public/uploads/rules/avoid-deleting-records-by-flagging-them-as-isdeleted/rule.mdx b/public/uploads/rules/retain-deleted-records-with-a-soft-delete/rule.mdx similarity index 77% rename from public/uploads/rules/avoid-deleting-records-by-flagging-them-as-isdeleted/rule.mdx rename to public/uploads/rules/retain-deleted-records-with-a-soft-delete/rule.mdx index f8ed51fd62e..efe8a01f563 100644 --- a/public/uploads/rules/avoid-deleting-records-by-flagging-them-as-isdeleted/rule.mdx +++ b/public/uploads/rules/retain-deleted-records-with-a-soft-delete/rule.mdx @@ -1,7 +1,7 @@ --- type: rule -title: Data - Do you avoid deleting records by flagging them as IsDeleted (aka Soft Delete)? -uri: avoid-deleting-records-by-flagging-them-as-isdeleted +title: Data - Do you use Soft Delete to retain deleted records? +uri: retain-deleted-records-with-a-soft-delete categories: - category: categories/software-engineering/rules-to-better-sql-databases-developers.mdx authors: @@ -10,6 +10,7 @@ authors: redirects: - data-do-you-avoid-deleting-records-by-flagging-them-as-isdeleted-aka-soft-delete - data-do-you-avoid-deleting-records-by-flagging-them-as-isdeleted-(aka-soft-delete) + - do-you-know-you-can-retain-deleted-records-with-a-soft-delete guid: 56fff82d-9ed7-4aee-ab22-68e4c61fe162 seoDescription: Avoid deleting records by flagging them as IsDeleted (aka Soft Delete) and instead keep historical data intact. created: 2019-11-25T19:14:13.000Z @@ -37,7 +38,7 @@ When users are deleting a lot of records as part of normal operations - they can * Depending on your interface design, you may have to join to parent tables to ensure that deleted child records do not appear. Typically, the interface would be designed in such a way that you would not need be able to created new records based on the deleted items (e.g. you cannot create a new order record for a customer that is deleted). Performance of queries can potentially suffer if you have to do these joins. * While storage space is very cheap, you are not removing records from your database. You may need to archive records if the number of deleted records becomes large. -### Best Approach for Implementing Soft Delete in EF Core for modern web application +## Best approach for implementing Soft Delete in EF Core for modern web applications ### 1. `ISoftDeleteEntity` Interface @@ -67,17 +68,35 @@ Override the default delete behavior using EF Core interceptors by using an inte ```chsarp public class SoftDeleteInterceptor : SaveChangesInterceptor { - public override InterceptionResult SavingChanges(DbContextEventData eventData, InterceptionResult result) + public override InterceptionResult SavingChanges( + DbContextEventData eventData, + InterceptionResult result) { - foreach (var entry in eventData.Context.ChangeTracker.Entries()) + UpdateEntities(eventData.Context); + return base.SavingChanges(eventData, result); + } + + public override ValueTask> SavingChangesAsync( + DbContextEventData eventData, + InterceptionResult result, + CancellationToken cancellationToken) + { + UpdateEntities(eventData.Context); + return base.SavingChangesAsync(eventData, result, cancellationToken); + } + + private static void UpdateEntities(DbContext? context) + { + if (context is null) return; + + foreach (var entry in context.ChangeTracker.Entries()) { if (entry.State == EntityState.Deleted) { - entry.Entity.IsDeleted = true; entry.State = EntityState.Modified; + entry.Entity.IsDeleted = true; } } - return base.SavingChanges(eventData, result); } } ``` @@ -119,16 +138,13 @@ Also see [Using Audit Tools](/use-temporal-tables-to-audit-data-changes) for a figure="" /> -### Soft Delete in Dynamic 365/ Dataverse (CRM) +## Soft Delete in Dynamic 365/ Dataverse (CRM) In Dynamics 365 you rarely hard-delete. The platform already supports soft delete via record status — so deactivate instead of delete, and make any real deletion a reviewed, reversible, 2-step process. -1\. Deactivate the record - -2\. Mark the affected records with an identifiable marker and run the change under a dedicated service account, so they're easy to filter, review and reverse. - -3\. Present the draft list of records for sign-off before any hard delete. - -4\. Run the built-in Bulk Record Deletion job with tight filters, e.g. Status Inactive AND ModifiedBy \[service account] AND ModifiedOn today. +1. Deactivate the record +2. Mark the affected records with an identifiable marker and run the change under a dedicated service account, so they're easy to filter, review and reverse +3. Present the draft list of records for sign-off before any hard delete +4. Run the built-in Bulk Record Deletion job with tight filters, e.g. Status Inactive AND ModifiedBy \[service account] AND ModifiedOn today