У меня есть блок кода, который работает в TransactionScope, и внутри этого блока кода я делаю несколько вызовов в БД. Выбирает, обновляет, создает и удаляет всю гамму. Когда я выполняю мое удаление, я выполняю его с использованием метода расширения SqlCommand, который будет автоматически повторно отправлять запрос, если он блокируется, поскольку этот запрос может потенциально попасть в тупик.
Я считаю, что проблема возникает, когда срабатывает тупик, и функция пытается повторно отправить запрос. Это ошибка, которую я получаю:
Транзакция, связанная с текущим соединением, завершена, но не удалена. Транзакция должна быть удалена до того, как соединение будет использоваться для выполнения операторов SQL.
Это простой код, выполняющий запрос (весь код ниже выполняется при использовании TransactionScope):
using (sqlCommand.Connection = new SqlConnection(ConnectionStrings.App))
{
sqlCommand.Connection.Open();
sqlCommand.ExecuteNonQueryWithDeadlockHandling();
}
Вот метод расширения, который повторяет тупиковый запрос:
public static class SqlCommandExtender
{
private const int DEADLOCK_ERROR = 1205;
private const int MAXIMUM_DEADLOCK_RETRIES = 5;
private const int SLEEP_INCREMENT = 100;
public static void ExecuteNonQueryWithDeadlockHandling(this SqlCommand sqlCommand)
{
int count = 0;
SqlException deadlockException = null;
do
{
if (count > 0) Thread.Sleep(count * SLEEP_INCREMENT);
deadlockException = ExecuteNonQuery(sqlCommand);
count++;
}
while (deadlockException != null && count < MAXIMUM_DEADLOCK_RETRIES);
if (deadlockException != null) throw deadlockException;
}
private static SqlException ExecuteNonQuery(SqlCommand sqlCommand)
{
try
{
sqlCommand.ExecuteNonQuery();
}
catch (SqlException exception)
{
if (exception.Number == DEADLOCK_ERROR) return exception;
throw;
}
return null;
}
}
Ошибка на линии:
sqlCommand.ExecuteNonQuery();