System.Data.SqlClient.SqlException después de CREATE / ALTER / PRINT
Vengo de otras 2 preguntas y estoy tratando de entender por qué ocurre esta excepción.
Entity Framework seed -> SqlException: restablecer la conexión da como resultado un estado diferente al inicio de sesión inicial. El inicio de sesión falla. resultados-en-un-dif
¿Qué significa "Restablecer la conexión"? System.Data.SqlClient.SqlException (0x80131904)
Este código reproduce la excepción.
string dbName = "TESTDB";
Run("master", $"CREATE DATABASE [{dbName}]"); Run(dbName, $"ALTER DATABASE [{dbName}] COLLATE Latin1_General_100_CI_AS");
Run(dbName, "PRINT 'HELLO'");
void Run(string catalog, string script)
{
var cnxStr = new SqlConnectionStringBuilder
{
DataSource = serverAndInstance,
UserID = user,
Password = password,
InitialCatalog = catalog
};
using var cn = new SqlConnection(cnxStr.ToString());
using var cm = cn.CreateCommand();
cn.Open();
cm.CommandText = script;
cm.ExecuteNonQuery();
}
El stacktrace completo es
Unhandled Exception: System.Data.SqlClient.SqlException: Resetting the connection results in a different state than the initial login. The login fails.
Login failed for user 'user'.
Cannot continue the execution because the session is in the kill state.
A severe error occurred on the current command. The results, if any, should be discarded.
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async, Int32 timeout, Boolean asyncWrite)
at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry)
at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
...
Si cambio de la primera Run(dbName...a la Run("master"...que funciona muy bien. Entonces, está relacionado con la ejecución ALTER DATABASEen el contexto de la misma base de datos.
¿Qué significa "Restablecer la conexión"? ¿Por qué la sesión está "en estado de interrupción"? ? ¿Debo evitar ejecutar declaraciones "ALTER" dentro de la misma base de datos? ¿Por qué?
Respuestas
El error "Restablecer la conexión da como resultado un estado diferente al inicio de sesión inicial. El inicio de sesión falla". se debe a que se reutiliza una conexión agrupada después del cambio de estado de la base de datos (cambio de clasificación de la base de datos). A continuación, se muestra lo que sucede internamente que conduce al error.
Cuando se ejecuta este código:
Run(dbName, $"ALTER DATABASE [{dbName}] COLLATE Latin1_General_100_CI_AS");
ADO.NET busca una conexión agrupada existente haciendo coincidir la cadena de conexión y el contexto de seguridad. No se encuentra ninguno porque la cadena de conexión de la conexión agrupada existente (de la CREATE DATABASEconsulta) es diferente ( masterbase de datos en lugar de TESTDB). ADO.NET luego crea una nueva conexión, que incluye el establecimiento de una conexión TCP / IP, autenticación e inicialización de sesión de SQL Server. La ALTER DATABASEconsulta se ejecuta en esta nueva conexión. La conexión se agrega al grupo de conexiones cuando se elimina (sale del usingalcance).
Entonces esto se ejecuta:
Run(dbName, "PRINT 'HELLO'");
ADO.NET encuentra la TESTDBconexión agrupada existente y la usa en lugar de crear una instancia de una nueva conexión. Cuando el PRINTcomando se envía a SQL Server, la solicitud de TDS incluye un indicador de conexión de restablecimiento para indicar que es una conexión agrupada reutilizada. Esto hace que SQL Server invoque internamente sp_reset_connectionpara realizar trabajos de limpieza como deshacer transacciones no confirmadas, eliminar tablas temporales, cerrar sesión, iniciar sesión, etc.) como se detalla aquí . Sin embargo, sp_reset_connectionno se puede revertir la conexión a la clasificación inicial debido al cambio de clasificación de la base de datos, lo que resulta en un error de inicio de sesión.
A continuación se muestran algunas técnicas para evitar el error. Sugiero la opción 3.
invocar el
SqlConnection.ClearAllPools()método estático después de cambiar la colaciónEspecifique en
masterlugar deTESTDBpara elALTER DATABASEcomando para que la conexión agrupada 'maestra' existente se reutilice en lugar de crear una nueva conexión. ElPRINTcomando subsiguiente creará una nueva conexión paraTESTDBya que no existe una en el grupo.especificar la intercalación en la
CREATE DATABASEdeclaración y eliminar elALTER DATABASEcomando por completo