如何为Entity Framework代码优先迁移设置隔离级别

时间:2014-04-17 07:57:21

标签: c# sql-server entity-framework entity-framework-6 ef-migrations

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

  

您只能在READ COMMITTED或中指定READPAST锁   REPEATABLE READ隔离级别

之前有一些问题(here),但它们完全无法解决根本原因:实体框架迁移在Serializable隔离级别运行(如SQL Server分析器中清楚地显示的那样)。

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

    TransactionScope

    期间,似乎忽略了
  • Database.Initialize()(为交易设置隔离级别的经典方法)

  • 最近推出的Database.BeginTransaction(isolationLevel)实际上是在开始新事务之前尝试初始化数据库,因此无法使用。

已知的解决方法

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

  2. 使用显式迁移,并使用类似

    的方法启动每个Up()Down()方法

    Sql(“set transaction isolation level read committed”);

  3. 这很有效,但由于开发人员通常不使用复制数据库,因此不方便且容易出错。

2 个答案:

答案 0 :(得分:21)

创建自己的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 :(得分:1)

您可以在迁移代码中编写和执行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);
}

更改&#34; ALLOW_SNAPSHOT_ISOLATION&#34;到你的隔离级别。