Pendekatan yang lebih disukai
Saya mendapat kesan bahwa yang berikut ini sudah diuji oleh orang lain, terutama berdasarkan beberapa komentar. Tetapi pengujian saya menunjukkan bahwa kedua metode ini memang bekerja pada tingkat DB, bahkan ketika menghubungkan melalui .NET SqlClient
. Ini telah diuji dan diverifikasi oleh orang lain.
Seluruh server
Anda dapat mengatur pengaturan konfigurasi server opsi pengguna menjadi apa pun yang saat ini dilakukan dengan bit OR
64 (nilai untuk ARITHABORT
). Jika Anda tidak menggunakan bit-wise OR ( |
) tetapi sebaliknya melakukan penugasan langsung ( =
) maka Anda akan menghapus semua opsi lain yang sudah ada yang diaktifkan.
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
Tingkat basis data
Ini dapat diatur per-basis data melalui ALTER DATABASE SET :
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;
Pendekatan alternatif
Berita yang tidak begitu baik adalah bahwa saya telah melakukan banyak pencarian pada topik ini, hanya untuk menemukan bahwa selama bertahun-tahun banyak orang lain telah melakukan banyak pencarian pada topik ini, dan tidak ada cara untuk mengkonfigurasi perilaku dari SqlClient
. Beberapa dokumentasi MSDN menyiratkan bahwa hal itu dapat dilakukan melalui ConnectionString, tetapi tidak ada kata kunci yang memungkinkan untuk mengubah pengaturan ini. Dokumen lain menyiratkan itu dapat diubah melalui Konfigurasi Jaringan / Manajer Konfigurasi Klien, tetapi itu sepertinya juga tidak mungkin. Karenanya, dan sayangnya, Anda harus menjalankannya SET ARITHABORT ON;
secara manual. Berikut adalah beberapa cara untuk dipertimbangkan:
JIKA Anda menggunakan Entity Framework 6 (atau yang lebih baru), Anda dapat mencoba:
Gunakan Database.ExecuteSqlCommand : context.Database.ExecuteSqlCommand("SET ARITHABORT ON;");
Idealnya ini akan dieksekusi sekali, setelah membuka koneksi DB, dan tidak per setiap permintaan.
Buat interseptor melalui:
Ini akan memungkinkan Anda untuk memodifikasi SQL sebelum dijalankan, dalam hal ini Anda hanya dapat awalan dengan: SET ARITHABORT ON;
. Kelemahan di sini adalah bahwa itu akan menjadi per setiap permintaan, kecuali Anda menyimpan variabel lokal untuk menangkap status apakah itu telah dieksekusi dan diuji untuk setiap kali (yang sebenarnya bukan pekerjaan ekstra, tetapi menggunakan ExecuteSqlCommand
adalah mungkin lebih mudah).
Salah satu dari mereka akan memungkinkan Anda untuk menangani ini di satu tempat tanpa mengubah kode yang ada.
ELSE , Anda bisa membuat metode pembungkus yang melakukan ini, mirip dengan:
public static SqlDataReader ExecuteReaderWithSetting(SqlCommand CommandToExec)
{
CommandToExec.CommandText = "SET ARITHABORT ON;\n" + CommandToExec.CommandText;
return CommandToExec.ExecuteReader();
}
dan kemudian hanya mengubah _Reader = _Command.ExecuteReader();
referensi saat ini menjadi _Reader = ExecuteReaderWithSetting(_Command);
.
Melakukan hal ini juga memungkinkan pengaturan ditangani di satu lokasi sementara hanya memerlukan perubahan kode yang minimal dan sederhana yang sebagian besar dapat dilakukan melalui Temukan & Ganti.
Lebih baik lagi ( Lain Bagian 2), karena ini adalah pengaturan tingkat koneksi, itu tidak perlu dieksekusi per setiap panggilan SqlCommand.Execute __ (). Jadi alih-alih membuat pembungkus untuk ExecuteReader()
, buat pembungkus untuk 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;
}
Dan kemudian ganti saja _Connection.Open();
referensi yang ada menjadi OpenAndSetArithAbort(_Connection);
.
Kedua ide di atas dapat diimplementasikan dengan gaya OO yang lebih banyak dengan membuat Kelas yang memperluas SqlCommand atau SqlConnection.
Atau Lebih Baik lagi ( Else Part 3), Anda bisa membuat event handler untuk Connection StateChange dan mengatur properti ketika koneksi berubah dari Closed
menjadi Open
sebagai berikut:
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();
}
}
}
Dengan itu, Anda hanya perlu menambahkan berikut ini ke setiap tempat di mana Anda membuat SqlConnection
instance:
_Connection.StateChange += new StateChangeEventHandler(OnStateChange);
Tidak diperlukan perubahan kode yang ada. Saya baru saja mencoba metode ini di aplikasi konsol kecil, menguji dengan mencetak hasilnya SELECT SESSIONPROPERTY('ARITHABORT');
. Itu kembali 1
, tetapi jika saya menonaktifkan Event Handler, itu kembali 0
.
Demi kelengkapan, berikut adalah beberapa hal yang tidak berfungsi (baik sama sekali atau tidak seefektif):
- Pemicu Logon : Pemicu, bahkan ketika berjalan di sesi yang sama, dan bahkan jika berjalan dalam transaksi yang dimulai secara eksplisit, masih merupakan sub-proses dan karenanya pengaturannya (
SET
perintah, tabel sementara lokal, dll.) Bersifat lokal untuk itu dan tidak bertahan akhir dari sub-proses itu.
- Menambahkan
SET ARITHABORT ON;
ke awal setiap prosedur tersimpan:
- ini membutuhkan banyak pekerjaan untuk proyek yang ada, terutama karena jumlah prosedur tersimpan meningkat
- ini tidak membantu permintaan ad hoc