如何为实体框架代码优先迁移设置隔离级别

Posted

技术标签:

【中文标题】如何为实体框架代码优先迁移设置隔离级别【英文标题】:How to set the isolation level for Entity Framework CodeFirst Migrations 【发布时间】:2014-06-01 09:36:48 【问题描述】:

如果您针对为 SQL Server 复制发布的表运行实体框架迁移(自动或显式),则会收到以下错误:

您只能在 READ COMMITTED 或 REPEATABLE READ 隔离级别

之前有关于此的问题 (here),但他们完全无法解决根本原因:Entity Framework 迁移在 Serializable 隔离级别运行(如在SQL Server 探查器)。

对于结构更改事务来说,这是一个安全的选择,但它与已发布的 sql server 表不兼容。与dbContext.SaveChanges() 事务中使用的默认 READ COMMITED SNAPSHOT 级别不同,我还没有找到一种方法来实际为代码中的迁移设置不同的隔离级别:

TransactionScope(为事务设置隔离级别的经典方法)在Database.Initialize() 期间似乎被忽略了

最近引入的Database.BeginTransaction(isolationLevel)实际上是在开始新事务之前尝试初始化数据库,所以不能使用。

已知的解决方法

    生成到 SQL 脚本的所有迁移。这可行,但基于代码的迁移是我不想错过的强大工具。

    使用显式迁移,并以类似的方式启动每个 Up()Down() 方法

    Sql("设置事务隔离级别读已提交");

这可行,但不方便且容易出错,因为开发人员通常不使用复制数据库。..

【问题讨论】:

【参考方案1】:

创建 onw Migrator 会有所帮助吗?

internal sealed class Configuration : DbMigrationsConfiguration<SupplierEntities>

  public Configuration()
  
    SetSqlGenerator("System.Data.SqlClient", new SqlMigrator());
  

  private class SqlMigrator : SqlServerMigrationSqlGenerator
  
    public override IEnumerable<MigrationStatement> Generate(
      IEnumerable<MigrationOperation> migrationOperations, string providerManifestToken)
    
      yield return new MigrationStatement  Sql = "set transaction isolation level read committed" ;
      foreach (var statement in base.Generate(migrationOperations, providerManifestToken))
        yield return statement;
    
  

【讨论】:

+1。多么棒的答案,这确实有助于代码优先设计的复制数据库,其中问题没有得到很好的记录。我没有帽子,但如果我戴了,它会朝你的方向倾斜【参考方案2】:

您可以在迁移代码中编写和执行 SQL:

在 SQL Server 2012 之前使用动态 SQL:

public override void Up()

     Sql("DECLARE @SQL NVARCHAR(4000) = 'ALTER DATABASE '+ DB_NAME() +' SET ALLOW_SNAPSHOT_ISOLATION ON' ; EXEC sp_executeSql @SQL;", true);

对于 SQL Server 2012 或更高版本:

public override void Up()

     Sql("ALTER DATABASE CURRENT SET ALLOW_SNAPSHOT_ISOLATION ON",true);

将“ALLOW_SNAPSHOT_ISOLATION”更改为您的隔离级别。

【讨论】:

以上是关于如何为实体框架代码优先迁移设置隔离级别的主要内容,如果未能解决你的问题,请参考以下文章

Spring框架默认事物隔离级别

为啥使用 Spring Data JPA 更新实体时@Transactional 隔离级别不起作用?

Hibernate中事务的隔离级别设置

如何创建具有快照隔离级别的 Flyway 模式历史记录?

搞清楚MySQL事务隔离级别

MySQL 事务的默认隔离级别是啥?可以解决幻读问题么?