如何为Entity Framework CodeFirst迁移设置隔离级别

16
如果您对发布到SQL Server复制的表运行实体框架迁移(自动或显式),则会出现以下错误:
只能在读提交或可重复读隔离级别中指定READPAST锁定。
此前曾有相关问题(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");

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

2个回答

22

创建自己的迁移工具是否有帮助?

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. 真是个棒极了的答案,这对于代码优先设计的复制数据库非常有帮助,因为这个问题并没有很好的文档记录。我没有帽子,但如果我有的话,我会向你致敬。 - Patrick McCurley

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”更改为您的隔离级别。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接