首页 > 解决方案 > 使用 EF6,如何全局设置事务隔离级别等连接属性?

问题描述

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

标签: entity-frameworkentity-framework-6

解决方案


在找到可行的解决方案之前,我尝试了几种不起作用的方法。没用的是:

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

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

失败#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 源代码是理解它们的最佳方式。静态方法是查找不同类型拦截器的DbInterception.Add良好起点。Find All References on different dispatcher 方法显示了拦截器的使用位置。


推荐阅读