DEV Community

Rohit Cdy
Rohit Cdy

Posted on • Updated on

Implementing Soft Delete With EF Core.

Soft Delete with EF Core.

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; }
}
Enter fullscreen mode Exit fullscreen mode
  • 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);
    }
}

Enter fullscreen mode Exit fullscreen mode
  • 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;
         */
    }
}

Enter fullscreen mode Exit fullscreen mode
  • Register SoftDeleteIntercepter with dependency injection.
services.AddSingleton<SoftDeleteInterceptor>();
services.AddDbContext<ApplicationDbContext>(
    sp, options)=>options
        .UseSqlServer(connectionString)
        .AddInterceptor(
               sp.GetRequiredService<SoftDeleteInterceptor>()));

Enter fullscreen mode Exit fullscreen mode
  • 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; }
}

Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)