System.Data.SqlClient.SqlException после CREATE / ALTER / PRINT
У меня еще 2 вопроса, и я пытаюсь понять, почему происходит это исключение.
Entity Framework seed -> SqlException: сброс соединения приводит к состоянию, отличному от состояния первоначального входа в систему. Не удается войти в систему. результаты в отличии
Что значит «Сброс соединения»? System.Data.SqlClient.SqlException (0x80131904)
Этот код воспроизводит исключение.
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();
}
Полная трассировка стека
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()
...
Если бы я изменить первый Run(dbName...на Run("master"...это работает отлично. Так что это связано с запуском ALTER DATABASEв контексте той же базы данных
Что значит «Сброс соединения»? Почему сеанс «в состоянии уничтожения». ? Следует ли мне избегать выполнения операторов ALTER в одной базе данных? Почему?
Ответы
Ошибка «Сброс соединения приводит к состоянию, отличному от первоначального входа в систему. Вход не выполняется». возникает из-за того, что объединенное соединение повторно используется после изменения состояния базы данных (изменение параметров сортировки базы данных). Ниже показано, что происходит внутри, что приводит к ошибке.
Когда этот код запускается:
Run(dbName, $"ALTER DATABASE [{dbName}] COLLATE Latin1_General_100_CI_AS");
ADO.NET ищет существующее объединенное соединение, сопоставляя строку соединения и контекст безопасности. Ничего не найдено, так как строка подключения существующего объединенного соединения (из CREATE DATABASEзапроса) отличается ( masterбаза данных вместо TESTDB). Затем ADO.NET создает новое соединение, которое включает установление соединения TCP / IP, аутентификацию и инициализацию сеанса SQL Server. ALTER DATABASEЗапрос выполняется на новом подключении. Соединение добавляется в пул соединений при удалении (выходит за пределы usingобласти).
Затем это работает:
Run(dbName, "PRINT 'HELLO'");
ADO.NET находит существующее объединенное TESTDBсоединение и использует его вместо создания нового соединения. Когда PRINTкоманда отправляется на SQL Server, запрос TDS включает флаг сброса соединения, чтобы указать, что это повторно используемое объединенное соединение. Это приводит к внутреннему вызову SQL Server для sp_reset_connectionвыполнения работы по очистке, такой как откат незафиксированных транзакций, удаление временных таблиц, выход из системы, вход в систему и т. Д., Как подробно описано здесь . Однако sp_reset_connectionневозможно вернуть соединение к исходному параметру сортировки из-за изменения параметров сортировки базы данных, что приводит к ошибке входа в систему.
Ниже приведены некоторые методы, позволяющие избежать ошибки. Предлагаю вариант 3.
вызвать статический
SqlConnection.ClearAllPools()метод после изменения сопоставленияУкажите
masterвместоTESTDBдляALTER DATABASEкоманды, чтобы существующее «главное» объединенное соединение использовалось повторно вместо создания нового соединения. ПоследующаяPRINTкоманда затем создаст новое соединение,TESTDBпоскольку его нет в пуле.укажите сопоставление в
CREATE DATABASEинструкции и полностью удалитеALTER DATABASEкоманду