Dường như cách tiếp cận ưa thích
Tôi có ấn tượng rằng những điều sau đây đã được kiểm tra bởi những người khác, đặc biệt là dựa trên một số ý kiến. Nhưng thử nghiệm của tôi cho thấy hai phương thức này thực sự hoạt động ở cấp độ DB, ngay cả khi kết nối qua .NET SqlClient
. Những người này đã được kiểm tra và xác minh bởi những người khác.
Toàn máy chủ
Bạn có thể đặt cài đặt cấu hình máy chủ tùy chọn người dùng thành bất cứ thứ gì hiện đang được chỉnh sửa bit OR
với 64 (giá trị cho ARITHABORT
). Nếu bạn không sử dụng bit OR ( |
) mà thay vào đó hãy thực hiện một phép gán thẳng ( =
) thì bạn sẽ xóa sạch mọi tùy chọn hiện có khác đã được bật.
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
Cấp cơ sở dữ liệu
Điều này có thể được đặt cho mỗi cơ sở dữ liệu thông qua 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;
Phương pháp thay thế
Một tin không vui là tôi đã tìm kiếm rất nhiều về chủ đề này, chỉ để thấy rằng trong nhiều năm qua, rất nhiều người khác đã tìm kiếm rất nhiều về chủ đề này và không có cách nào để định cấu hình hành vi của SqlClient
. Một số tài liệu MSDN ngụ ý rằng nó có thể được thực hiện thông qua ConnectionString, nhưng không có Từ khóa nào cho phép thay đổi các cài đặt này. Một tài liệu khác ngụ ý nó có thể được thay đổi thông qua Trình quản lý cấu hình / cấu hình mạng máy khách, nhưng điều đó dường như cũng không thể. Do đó, và thật không may, bạn sẽ cần phải thực hiện SET ARITHABORT ON;
thủ công. Dưới đây là một số cách để xem xét:
NẾU bạn đang sử dụng Entity Framework 6 (hoặc mới hơn), bạn có thể thử:
Sử dụng cơ sở dữ liệu.ExecuteSqlCommand : context.Database.ExecuteSqlCommand("SET ARITHABORT ON;");
Lý tưởng nhất là việc này sẽ được thực hiện một lần, sau khi mở kết nối DB và không phải cho mỗi truy vấn.
Tạo một thiết bị đánh chặn thông qua một trong hai:
Điều này sẽ cho phép bạn sửa đổi SQL trước khi nó được thực thi, trong trường hợp đó bạn có thể chỉ cần thêm tiền tố vào : SET ARITHABORT ON;
. Nhược điểm ở đây là nó sẽ theo từng truy vấn, trừ khi bạn lưu trữ một biến cục bộ để nắm bắt trạng thái của nó có được thực thi hay không và kiểm tra cho mỗi lần đó (thực sự không phải là nhiều công việc phụ, nhưng sử dụng ExecuteSqlCommand
là có lẽ dễ dàng hơn).
Một trong hai sẽ cho phép bạn xử lý việc này tại một điểm mà không thay đổi bất kỳ mã hiện có nào.
ELSE , bạn có thể tạo một phương thức trình bao bọc thực hiện điều này, tương tự như:
public static SqlDataReader ExecuteReaderWithSetting(SqlCommand CommandToExec)
{
CommandToExec.CommandText = "SET ARITHABORT ON;\n" + CommandToExec.CommandText;
return CommandToExec.ExecuteReader();
}
và sau đó chỉ cần thay đổi các _Reader = _Command.ExecuteReader();
tài liệu tham khảo hiện tại để được _Reader = ExecuteReaderWithSetting(_Command);
.
Làm điều này cũng cho phép xử lý cài đặt ở một vị trí trong khi chỉ yêu cầu thay đổi mã đơn giản và tối thiểu có thể được thực hiện chủ yếu thông qua Tìm & Thay thế.
Hơn thế nữa ( khác Phần 2), vì đây là một thiết lập mức độ kết nối, nó không cần phải được thực hiện cho mỗi SqlCommand.Execute __ () gọi. Vì vậy, thay vì tạo một trình bao bọc cho ExecuteReader()
, hãy tạo một trình bao bọc cho 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;
}
Và sau đó chỉ cần thay thế các _Connection.Open();
tài liệu tham khảo hiện có OpenAndSetArithAbort(_Connection);
.
Cả hai ý tưởng trên đều có thể được thực hiện theo phong cách OO hơn bằng cách tạo ra một Lớp mở rộng SqlCommand hoặc SqlConnection.
Hoặc Hơn thế nữa ( khác Phần 3), bạn có thể tạo một event handler cho Connection StateChange và có nó thiết lập thuộc tính khi thay đổi kết nối từ Closed
để Open
như sau:
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();
}
}
}
Với vị trí đó, bạn chỉ cần thêm các mục sau vào mỗi nơi bạn tạo một SqlConnection
thể hiện:
_Connection.StateChange += new StateChangeEventHandler(OnStateChange);
Không có thay đổi đối với mã hiện tại là cần thiết. Tôi vừa thử phương pháp này trong một ứng dụng bảng điều khiển nhỏ, thử nghiệm bằng cách in kết quả SELECT SESSIONPROPERTY('ARITHABORT');
. Nó trả về 1
, nhưng nếu tôi vô hiệu hóa Trình xử lý sự kiện, nó sẽ trả về 0
.
Để hoàn thiện, đây là một số điều không hoạt động (hoàn toàn hoặc không hiệu quả):
- Logon Triggers : Triggers, ngay cả khi đang chạy trong cùng một phiên và ngay cả khi đang chạy trong một giao dịch được bắt đầu rõ ràng, vẫn là một quy trình phụ và do đó các cài đặt của nó (
SET
các lệnh, bảng tạm thời, v.v.) là cục bộ và không tồn tại kết thúc quá trình phụ đó.
- Thêm
SET ARITHABORT ON;
vào đầu mỗi thủ tục được lưu trữ:
- điều này đòi hỏi rất nhiều công việc cho các dự án hiện có, đặc biệt là khi số lượng thủ tục lưu trữ tăng lên
- điều này không giúp truy vấn ad hoc