c# - studio - Cómo establecer el nivel de aislamiento para Entity Framework CodeFirst Migrations
enum entity framework (2)
Si ejecuta una migración del marco de la entidad (automática o explícita) en las tablas publicadas para la replicación de SQL Server, obtendrá el siguiente error:
Solo puede especificar el bloqueo READPAST en los niveles de aislamiento READ COMMITTED o REPEATABLE READ
Ha habido preguntas sobre esto antes ( here ), pero fallan por completo para abordar la causa subyacente: la migración de Entity Framework se ejecuta en el nivel de aislamiento Serializable
(como se muestra claramente en el perfilador de SQL Server).
Esta es una opción segura para una transacción que cambia la estructura, pero simplemente no es compatible con las tablas de servidor SQL publicadas. A diferencia del nivel de SNAPSHOT de READ COMMITED usado en las transacciones dbContext.SaveChanges()
, todavía no he encontrado una manera de establecer un nivel de aislamiento diferente para las migraciones en el código:
TransactionScope
(la forma clásica de establecer el nivel de aislamiento para transacciones) parece ignorarse duranteDatabase.Initialize()
La recientemente introducida
Database.BeginTransaction(isolationLevel)
intenta inicializar la base de datos antes de iniciar la nueva transacción, por lo que no se puede usar.
Soluciones conocidas
Generar todas las migraciones a script SQL. Esto funciona, pero las migraciones basadas en código son un instrumento poderoso que no me gustaría perder.
Use migraciones explícitas e inicie cada método
Up()
yDown()
con algo comoSql ("se confirmó la lectura del nivel de aislamiento de la transacción");
Esto funciona, pero es inconveniente y propenso a errores, ya que los desarrolladores no suelen trabajar con una base de datos replicada.
¿Le ayudaría crear su 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;
}
}
}
Puedes escribir y ejecutar SQL en tu código de migración:
Antes de que SQL Server 2012 use SQL dinámico:
public override void Up()
{
Sql("DECLARE @SQL NVARCHAR(4000) = ''ALTER DATABASE ''+ DB_NAME() +'' SET ALLOW_SNAPSHOT_ISOLATION ON'' ; EXEC sp_executeSql @SQL;", true);
}
Para SQL Server 2012 o posterior:
public override void Up()
{
Sql("ALTER DATABASE CURRENT SET ALLOW_SNAPSHOT_ISOLATION ON",true);
}
Cambie "ALLOW_SNAPSHOT_ISOLATION" a su nivel de aislamiento.