EF Core Query interceptor

Query interceptor in EF core allows developer to intercept the query before or after the execution. This provides the ability of interception, modification, or suppression of the query execution.

How to use Query Interceptor into code

EF core exposes DbCommandInterceptor base class, this base class is abstract class and has overridable methods which could be hooked into a class which is inherited DbCommandInterceptor class. Since Entity framework internally uses ADO.NET for database operations, DbCommandInterceptor class provides lifecycle methods for a query.

Code example

Create a class that inherits DbCommandInterceptor

public class QueryInterceptor :DbCommandInterceptor {
}

Override the lifecycle method which you are interested in

public class QueryInterceptor :DbCommandInterceptor {
    // runs before a query is executed
    public override InterceptionResult<DbDataReader> ReaderExecuting(DbCommand command,CommandEventData eventData, InterceptionResult<DbDataReader> result){
        Console.WriteLine($"Before Query execution. Query : {command.CommandText}");
        return result;
    }
    // runs after a query is excuted
    public override DbDataReader ReaderExecuted(DbCommand command, CommandExecutedEventData eventData, DbDataReader result) {
        Console.WriteLine($"After Query execution. Query : {command.CommandText}");
        return result;
    }        
}

DbCommandInterceptor provides async version of these methods to support asynchronous operations

public class QueryInterceptor :DbCommandInterceptor {
    public override ValueTask<InterceptionResult<DbDataReader>> ReaderExecutingAsync(DbCommand command, CommandEventData eventData, InterceptionResult<DbDataReader> result, CancellationToken cancellationToken = default){
        return base.ReaderExecutingAsync(command, eventData, result, cancellationToken);
    }
    public override ValueTask<DbDataReader> ReaderExecutedAsync(DbCommand command, CommandExecutedEventData eventData, DbDataReader result, CancellationToken cancellationToken = default){
        return base.ReaderExecutedAsync(command, eventData, result, cancellationToken);
    }
}

Register the interceptor with DbContext:

An interceptor could be added to context using two ways :

  • register while adding DbContext to services

      services.AddDbContext<ExampleContext>(opt => 
        opt.UseNpgsql(cfg.GetConnectionString("DefaultConnectionString"))
           .AddInterceptors (new QueryInterceptor()));
    
  • register inside OnConfiguring method of DbContext class

      public class ExampleContext : DbContext{
          protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder){
              base.OnConfiguring(optionsBuilder);
              optionsBuilder.AddInterceptors(new QueryInterceptor())
          }
      }
    

List of lifecycle methods available

Method NameDescription
CommandCanceled , CommandCanceledAsynccalled when a command is cancelled.
CommandCreatedAfter command creation but before execution.
[CommandCreating](learn.microsoft.com/en-us/dotnet/api/micros..)Before a command is created
CommandFailed, CommandFailedAsyncCalled when execution of a command has failed with an exception.
CommandInitializedCalled after EF has initialized CommandText and other command configuration.
DataReaderClosing, DataReaderClosingAsyncCalled just before EF intends to call Close().
DataReaderDisposingCalled when execution of a DbDataReader is about to be disposed.
NonQueryExecuted, NonQueryExecutedAsyncCalled immediately after EF calls ExecuteNonQuery().
[NonQueryExecuting](learn.microsoft.com/en-us/dotnet/api/micros..), [NonQueryExecutingAsync](learn.microsoft.com/en-us/dotnet/api/micros..)Called just before EF intends to call ExecuteNonQuery().
ReaderExecuted, ReaderExecutedAsyncCalled immediately after EF calls ExecuteReader().
[ReaderExecuting](learn.microsoft.com/en-us/dotnet/api/micros..), [ReaderExecutingAsync](learn.microsoft.com/en-us/dotnet/api/micros..)Called just before EF intends to call ExecuteReader().
ScalarExecuted, ScalarExecutedAsyncCalled immediately after EF calls ExecuteScalar().
[ScalarExecuting](learn.microsoft.com/en-us/dotnet/api/micros..), [ScalarExecutingAsync](learn.microsoft.com/en-us/dotnet/api/micros..)Called just before EF intends to call ExecuteScalar().

Resources

Did you find this article valuable?

Support Deepak Kumar Jain by becoming a sponsor. Any amount is appreciated!