Здається, переважний підхід
У мене було враження, що наступне було перевірено вже іншими, особливо на основі деяких коментарів. Але моє тестування показує, що ці два методи дійсно працюють на рівні БД, навіть при підключенні через .NET SqlClient
. Вони перевірені та перевірені іншими.
Загальносерверний
Ви можете встановити настройки конфігурації сервера параметрів користувачів такими, якими вони є в даний час, OR
з 64 (значення для ARITHABORT
). Якщо ви не використовуєте біт-мудрий АБО ( |
), а замість цього виконайте пряме призначення ( =
), ви викреслите будь-які інші існуючі параметри, які вже увімкнено.
DECLARE @Value INT;
SELECT @Value = CONVERT(INT, [value_in_use]) --[config_value] | 64
FROM sys.configurations sc
WHERE sc.[name] = N'user options';
IF ((@Value & 64) <> 64)
BEGIN
PRINT 'Enabling ARITHABORT...';
SET @Value = (@Value | 64);
EXEC sp_configure N'user options', @Value;
RECONFIGURE;
END;
EXEC sp_configure N'user options'; -- verify current state
Рівень бази даних
Це можна встановити на базу даних за допомогою НАСТРОЙКИ ДЛЯ ДАТАБАЗИ :
USE [master];
IF (EXISTS(
SELECT *
FROM sys.databases db
WHERE db.[name] = N'{database_name}'
AND db.[is_arithabort_on] = 0
))
BEGIN
PRINT 'Enabling ARITHABORT...';
ALTER DATABASE [{database_name}] SET ARITHABORT ON WITH NO_WAIT;
END;
Альтернативні підходи
Не надто гарна новина полягає в тому, що я зробив багато пошуків на цю тему, лише щоб виявити, що за ці роки багато інших зробили багато пошуків на цю тему, і немає способу налаштувати поведінку з SqlClient
. У деяких документах MSDN випливає, що це можна зробити через ConnectionString, але немає Ключових слів, які дозволяли б змінити ці налаштування. Інший документ означає, що його можна змінити через Менеджер конфігурації / конфігурації мережі клієнтів, але це також не представляється можливим. Отже, і, на жаль, вам потрібно буде виконати SET ARITHABORT ON;
вручну. Ось кілька способів розглянути:
Якщо ви використовуєте Entity Framework 6 (або новішу версію), ви можете спробувати:
Використовуйте Database.ExecuteSqlCommand : context.Database.ExecuteSqlCommand("SET ARITHABORT ON;");
В ідеалі це буде виконуватися один раз, після відкриття з'єднання БД, а не для кожного запиту.
Створіть перехоплювач за допомогою будь-якого:
Це дозволить вам змінити SQL перед виконанням, в цьому випадку ви можете просто префікс його: SET ARITHABORT ON;
. Недоліком тут є те , що він буде в кожному запиті, якщо ви не зберігати локальну змінну для фіксації стану або не було виконано і тест для цього кожен раз (який на самому ділі не так багато додаткової роботи, але з використанням ExecuteSqlCommand
в певно, простіше).
Жоден із них дозволить вам обробити це в одному місці, не змінюючи жодного наявного коду.
ELSE , ви можете створити метод обгортки, який робить це, аналогічно:
public static SqlDataReader ExecuteReaderWithSetting(SqlCommand CommandToExec)
{
CommandToExec.CommandText = "SET ARITHABORT ON;\n" + CommandToExec.CommandText;
return CommandToExec.ExecuteReader();
}
а потім просто змінити поточні _Reader = _Command.ExecuteReader();
посилання на _Reader = ExecuteReaderWithSetting(_Command);
.
Це також дозволяє обробляти налаштування в одному місці, вимагаючи лише мінімальних та спрощених змін коду, які в основному можна здійснити за допомогою Find & Replace.
Ще краще ( інша частина 2), оскільки це налаштування рівня з'єднання, його не потрібно виконувати для кожного виклику SqlCommand.Execute __ (). Тому замість створення обгортки для цього ExecuteReader()
створіть обгортку для Connection.Open()
:
public static void OpenAndSetArithAbort(SqlConnection MyConnection)
{
using (SqlCommand _Command = MyConnection.CreateCommand())
{
_Command.CommandType = CommandType.Text;
_Command.CommandText = "SET ARITHABORT ON;";
MyConnection.Open();
_Command.ExecuteNonQuery();
}
return;
}
А потім просто замініть існуючі _Connection.Open();
посилання на OpenAndSetArithAbort(_Connection);
.
Обидві вищевказані ідеї можуть бути реалізовані в більш стильовому стилі, створивши клас, який розширює або SqlCommand, або SqlConnection.
Або ще краще ( інша частина 3), ви можете створити обробник подій для Connection StateChange і встановити його властивість, коли з'єднання змінюється Closed
на Open
таке:
protected static void OnStateChange(object sender, StateChangeEventArgs args)
{
if (args.OriginalState == ConnectionState.Closed
&& args.CurrentState == ConnectionState.Open)
{
using (SqlCommand _Command = ((SqlConnection)sender).CreateCommand())
{
_Command.CommandType = CommandType.Text;
_Command.CommandText = "SET ARITHABORT ON;";
_Command.ExecuteNonQuery();
}
}
}
Маючи це на місці, вам потрібно лише додати наступне до кожного місця, де ви створюєте SqlConnection
екземпляр:
_Connection.StateChange += new StateChangeEventHandler(OnStateChange);
Ніяких змін до існуючого коду не потрібно. Я тільки що спробував цей метод у невеликому консольному додатку, перевіривши, надрукувавши результат SELECT SESSIONPROPERTY('ARITHABORT');
. Він повертається 1
, але якщо я відключу обробник подій, він повертається 0
.
Для повноти, ось деякі речі, які не працюють (взагалі чи не так ефективно):
- Тригери входу : Тригери навіть під час виконання одного і того ж сеансу, і навіть якщо він виконується в рамках явно розпочатої транзакції, все ще є підпроцесом, а значить, його налаштування (
SET
команди, локальні тимчасові таблиці тощо) є локальними для нього і не виживають закінчення цього підпроцесу.
- Додавання
SET ARITHABORT ON;
до початку кожної збереженої процедури:
- для цього потрібна велика робота для існуючих проектів, тим більше, що збільшується кількість збережених процедур
- це не допомагає спеціальним запитам