EF Core: Easily detect slow running queries, and modify hard deletes

Implementing a Performance Interceptor

using Microsoft.EntityFrameworkCore.Diagnostics;
using System.Diagnostics;

public class PerformanceInterceptor : DbCommandInterceptor
{
    private const long QuerySlowThreshold = 100; // milliseconds

    public override InterceptionResult<DbDataReader> ReaderExecuting(
        DbCommand command, 
        CommandEventData eventData, 
        InterceptionResult<DbDataReader> result)
    {
        Stopwatch stopwatch = Stopwatch.StartNew();

        var originalResult = base.ReaderExecuting(command, eventData, result);

        stopwatch.Stop();
        if (stopwatch.ElapsedMilliseconds > QuerySlowThreshold)
        {
            Console.WriteLine($"Slow Query Detected: {command.CommandText}");
        }

        return originalResult;
    }
}


Implementing Soft Deletes

public class MyEntity
{
    public Guid Id { get; set; }
    public bool IsDeleted { get; set; }
    // Other properties...
}

public class SoftDeleteInterceptor : SaveChangesInterceptor
{
    public override InterceptionResult<int> SavingChanges(
        DbContextEventData eventData, 
        InterceptionResult<int> result)
    {
        foreach (var entry in eventData.Context.ChangeTracker.Entries())
        {
            if (entry.State == EntityState.Deleted && entry.Entity is MyEntity entity)
            {
                entity.IsDeleted = true;
                entry.State = EntityState.Modified;
            }
        }

        return base.SavingChanges(eventData, result);
    }
}


Register the interceptor with your DbContext.

using Microsoft.EntityFrameworkCore;

public class SampleDbContext : DbContext
{
    public DbSet<MyEntity> SampleEntities { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer("Your_Connection_String");

        // Registering the PerformanceInterceptor
        optionsBuilder.AddInterceptors(new PerformanceInterceptor());

        // Registering the SoftDeleteInterceptor
        optionsBuilder.AddInterceptors(new SoftDeleteInterceptor());
    }   
}