Implementing Soft Delete With EF Core.
Tags: efcore, softdelete, softdeletewithefcore, softdeleteindotnetcore
Published: 2024-03-16 08:21:09


![Soft Delete with EF Core.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wjqv1sfq2c3qztpv0pzz.png)


## What is soft delete?

- Prevents permanent deletion of records.

- Flag set on record, indicating "delete".

- Allows for easy restoration and maintains data integrity.

## How to implement:

- **Create Marker Interface.**

Define a marker interface ISoftDelete to mark entities that support soft delete.

```
public interface ISoftDelete
{
    bool IsDeleted { get; set; }
    DateTime? DeleteOnUtc { get; set; }
}
```

- **Implement Soft Delete Interceptor.**

Create a class SoftDeleteInterceptor to handle soft deletes in EF Core.

```
public sealed class SoftDeleteInterceptor: SaveChangesInterceptor
{
    public override ValueTask<InterceptionResult<int>> SavingChangesAsync(
        DbContextEventData eventData,
        InterceptionResult<int> result,
        CancellationToken cancellationToken = default)
    {
        if (eventData.Context is null)
        {
            return base.SavingChangesAsync(eventData, result, cancellationToken);
        }

        IEnumerable<EntityEntry<ISoftDeletable>> entries =
            eventData.Context.ChangeTracker.Entries<ISoftDeletable>()
                .Where(e => e.State == EntityState.Deleted);

        foreach (EntityEntry<ISoftDeletable> softDeletable in entries)
        {
            softDeletable.State = EntityState.Modified;
            softDeletable.Entity.IsDeleted = true;
            softDeletable.Entity.DeletedOnUtc = DateTime.UtcNow;
        }

        return base.SavingChangesAsync(eventData, result, cancellationToken);
    }
}

```

- **Configure Application Context.**

Configure EF Core to use the soft delete interceptor and global query filters.
```
public class ApplicationDbContext: DbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }

    public DbSet<User> Users { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        // HasQueryFilter is used to filter soft-deleted data automatically.
        modelBuilder.Entity<User>().HasQueryFilter(r => !r.IsDeleted);
        
        modelBuilder.Entity<User>()
        .HasIndex(r=> r.IsDeleted)
        .HasFilter("IsDeleted=0");

        // This HasFilter method accepts the SQL filter for records that will be 
            included in the index.
        // You can also create a filtered index using SQL:
         /*
           Create index IX_Users_IsDeleted on User(IsDeleted) where IsDelete =0;
         */
    }
}

```

- **Register SoftDeleteIntercepter with dependency injection.**

```
services.AddSingleton<SoftDeleteInterceptor>();
services.AddDbContext<ApplicationDbContext>(
    sp, options)=>options
        .UseSqlServer(connectionString)
        .AddInterceptor(
               sp.GetRequiredService<SoftDeleteInterceptor>()));

```

- **Example Entity.**

Create an example entity Review implementing the soft delete marker interface.

```
public class User: ISoftDeletable
{
    public int Id { get; set; }
    public string UserName { get; set; }
    public bool IsDeleted { get; set; }
    public DateTime? DeletedOnUtc { get; set; }
}

```

## Benefits:

- Flexibility in managing data.
- Simplified queries with automatic exclusion of soft-deleted records.
- Improved performance with filtered indexes.

## Conclusion

- Soft delete ensures data integrity and flexibility in managing records without compromising performance.