使用 EF6,如何全局设置事务隔离级别等连接属性?

With EF6, how do I globally set connection properties such as transaction isolation level?

使用 Entity Framework 6、如何为 EF 打开的每个连接设置连接属性?例如,如果我想覆盖默认的事务隔离级别。某些属性(如事务隔离级别)无法使用连接字符串进行配置。

在找到有效的解决方案之前,我尝试了几种不同的方法,但均无效。不起作用的是:

失败 #1:在 DbContext 的工厂方法中,我调用 DbContext.Database.ExecuteSql 来设置连接的属性。 失败,因为 EF 在用于其他调用之前重置了连接。

失败 #2:使用 TransactionScopeDbContext.Database.BeginTransaction 覆盖 DbContext.SaveChangesDbContext.SaveChangesAsync 以将保存包装在具有指定隔离级别的事务中。这适用于保存更改,特别适用于隔离级别,但对查询或非隔离级别连接设置没有帮助。

失败 #3:添加了一个 IDbTransactionInterceptor 并实现了 IsolationLevelGettingIsolationLevelGot 但这些似乎只能改变当您查询事务隔离时返回的隔离级别级别在 EF 代码之外。 EF代码在创建交易时不使用这个。

成功:

实施 IDbConnectionInterceptor,实施 Opened,我在打开的连接上执行命令,在本例中是设置事务隔离级别。这影响了 EF 执行的每个命令,使用 SQL Profiler 确认。

步骤:

创建 System.Data.Entity.Infrastructure.Interception.IDbConnectionInterceptor

的实现
public class ConnectionIsolationLevelInterceptor: IDbConnectionInterceptor
{
    // Have empty implementations for all unused IDbConnectionInterceptor methods
    public void BeganTransaction(DbConnection connection, BeginTransactionInterceptionContext interceptionContext)
    {
    }

    ...
    ... all other unused methods
    ... 

    public void Opened(DbConnection connection, DbConnectionInterceptionContext interceptionContext)
    {
        using (DbCommand command = connection.CreateCommand())
        {
            command.CommandText = "SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED";
            command.ExecuteNonQuery();
         }
    }
}

在应用程序初始化代码中,添加拦截器:

DbInterception.Add(new ConnectionIsolationLevelInterceptor());

旁注:有许多不同的拦截器。引用 EF 6 source code 是理解它们的最佳方式。 DbInterception.Add 静态方法是查找不同类型拦截器的良好起点。 Find All References on different dispatcher methods 显示拦截器的使用位置。