Entity Framework Extensions Transaction Interception
The DbTransactionInterceptor
is a class that can receive notifications when Entity Framework uses a transaction. You must override the method from this class.
To get this feature in your EF Core, install the Z.EntityFramework.Extensions.EFCore NuGet package or run the following command in Package Manager Console.
PM> Install-Package Z.EntityFramework.Extensions.EFCore
Create Interceptor
To implement transaction interception, we need to create a custom interceptor and register it accordingly. Entity Framework will call it whenever a transaction is used.
Let's create a new class EFTransactionInterceptor
that implements DbTransactionInterceptor
class which is available in Z.EntityFramework.Extensions.EFCore.
public class EFTransactionInterceptor : DbTransactionInterceptor { public override void Committed(DbTransaction transaction, DbTransactionInterceptionContext interceptionContext) { base.Committed(transaction, interceptionContext); LogInfo("EFTransactionInterceptor.Committed", interceptionContext.EventData.ToString()); } public override void Disposed(DbTransaction transaction, DbTransactionInterceptionContext interceptionContext) { base.Disposed(transaction, interceptionContext); LogInfo("EFTransactionInterceptor.Disposed", interceptionContext.EventData.ToString()); } public override void Error(DbTransaction transaction, DbTransactionInterceptionContext interceptionContext, Exception exception) { base.Error(transaction, interceptionContext, exception); LogInfo("EFTransactionInterceptor.Error", interceptionContext.EventData.ToString(), exception.Message); } public override void RolledBack(DbTransaction transaction, DbTransactionInterceptionContext interceptionContext) { base.RolledBack(transaction, interceptionContext); LogInfo("EFTransactionInterceptor.RolledBack", interceptionContext.EventData.ToString()); } public override void Started(DbTransaction transaction, DbTransactionInterceptionContext interceptionContext) { base.Started(transaction, interceptionContext); LogInfo("EFTransactionInterceptor.Started", interceptionContext.EventData.ToString()); } public override void Used(DbTransaction transaction, DbTransactionInterceptionContext interceptionContext) { base.Used(transaction, interceptionContext); LogInfo("EFTransactionInterceptor.Used", interceptionContext.EventData.ToString()); } private void LogInfo(string method, string data) { Console.WriteLine("Intercepted on: {0}: \n\t{1}", method, data); } private void LogInfo(string method, string data, string exception) { Console.WriteLine("Intercepted on: {0}: \n\t{1} \n\t{2}", method, data, exception); } }
This code writes connection information on the Console Window. The DbConnectionInterceptionContext
currently have the following properties:
- DbContext
- EventData which contains all information about this event.
Register Interceptor
Once a class that implements the interception has been created it can be registered using the DbInterception
class as shown below.
DbInterception.Add(new EFTransactionInterceptor());
You can add interceptors using the DbInterception.Add
method anywhere in your code such as, Application_Start
method or in the DbConfiguration
class, etc.
- Be careful not to execute
DbInterception.Add
for the same interceptor more than once, otherwise, you will get additional interceptor instances. - For example, if you add the logging interceptor twice, you will see two logs for every SQL query.
- In this example, we will register the interceptor in the
main
method.
You can also bind the interceptor to the context if you want to have information about context, but this step is optional.
public static EFTransactionInterceptor TransactionInterceptor = new EFTransactionInterceptor(); public class CurrentContext : DbContext { public CurrentContext() { this.BindInterceptor(TransactionInterceptor); } public DbSet<Customer> Customers { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer(@"Data Source=(localdb)\ProjectsV13;Initial Catalog=TestDB;"); } }
Now let's insert some data to the database and then retrieve the data from the database.
static void Main(string[] args) { DbInterception.Add(TransactionInterceptor); using (var context = new CurrentContext()) { var list = new List<Customer>(); list.Add(new Customer() { Name = "Customer_A", IsActive = true }); list.Add(new Customer() { Name = "Customer_B", IsActive = true }); list.Add(new Customer() { Name = "Customer_C", IsActive = true }); context.Customers.AddRange(list); context.SaveChanges(); } using (var context = new CurrentContext()) { var list = context.Customers.ToList(); } }
Let's run your application in debug mode, and you will see all the information related to transaction on the console window.
Intercepted on: EFTransactionInterceptor.Started: Beginning transaction with isolation level 'ReadCommitted'. Intercepted on: EFTransactionInterceptor.Committed: Committing transaction. Intercepted on: EFTransactionInterceptor.Disposed: Disposing transaction.
ZZZ Projects