วิธีที่ต้องการดูเหมือน
ฉันรู้สึกว่าสิ่งต่อไปนี้ผ่านการทดสอบแล้วโดยผู้อื่นโดยเฉพาะอย่างยิ่งจากความคิดเห็นบางส่วน แต่การทดสอบของฉันแสดงให้เห็นว่าทั้งสองวิธีทำแน่นอนการทำงานในระดับ DB แม้ในขณะที่เชื่อมต่อผ่าน SqlClient
.NET สิ่งเหล่านี้ได้รับการทดสอบและตรวจสอบโดยผู้อื่น
เซิร์ฟเวอร์กว้าง
คุณสามารถตั้งค่าการกำหนดค่าเซิร์ฟเวอร์ตัวเลือกผู้ใช้ให้เป็นแบบบิตที่ชาญฉลาดOR
ด้วย 64 (ค่าสำหรับARITHABORT
) หากคุณไม่ได้ใช้ bit-wise หรือ ( |
) แต่ทำการมอบหมายแบบตรง ( =
) คุณจะลบตัวเลือกอื่น ๆ ที่เปิดใช้งานอยู่
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
ฐานข้อมูลระดับ
สามารถตั้งค่าฐานข้อมูลผ่าน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;
แนวทางอื่น
ข่าวดีก็คือฉันได้ทำการค้นหาจำนวนมากในหัวข้อนี้เท่านั้นเพื่อที่จะพบว่าในช่วงหลายปีที่ผ่านมามีคนอื่นอีกหลายคนที่ได้ทำการค้นหามากมายในหัวข้อนี้และไม่มีวิธีกำหนดค่าพฤติกรรม SqlClient
ของ เอกสาร MSDN บางอย่างบอกเป็นนัยว่าสามารถทำได้ผ่าน ConnectionString แต่ไม่มีคำค้นหาที่จะอนุญาตให้ทำการเปลี่ยนแปลงการตั้งค่าเหล่านี้ เอกสารอื่นบอกเป็นนัยว่าสามารถเปลี่ยนแปลงได้ผ่านไคลเอนต์การกำหนดค่าเครือข่าย / เครื่องมือจัดการการกำหนดค่า แต่ไม่สามารถทำได้ ดังนั้นและค่อนข้างน่าเสียดายที่คุณจะต้องดำเนินการSET ARITHABORT ON;
ด้วยตนเอง ต่อไปนี้เป็นวิธีพิจารณา:
หากคุณใช้ Entity Framework 6 (หรือใหม่กว่า) คุณสามารถลองทำสิ่งใดสิ่งหนึ่งต่อไปนี้:
ใช้Database.ExecuteSqlCommand : โดยหลักแล้วcontext.Database.ExecuteSqlCommand("SET ARITHABORT ON;");
สิ่งนี้จะถูกเรียกใช้งานครั้งเดียวหลังจากเปิดการเชื่อมต่อฐานข้อมูลและไม่ต่อแต่ละแบบสอบถาม
สร้างinterceptorผ่าน:
นี้จะช่วยให้คุณสามารถปรับเปลี่ยน 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);
การทำเช่นนี้ยังช่วยให้สามารถจัดการการตั้งค่าในสถานที่เดียวในขณะที่ต้องการการเปลี่ยนแปลงรหัสขั้นต่ำและง่ายที่สุดที่สามารถทำได้ผ่านการค้นหาและแทนที่
ยังดีกว่า ( อื่น ๆส่วนที่ 2) เนื่องจากนี่เป็นการตั้งค่าระดับการเชื่อมต่อจึงไม่จำเป็นต้องดำเนินการสำหรับการเรียก SqlCommand แต่ละครั้งเรียกใช้ __ () ดังนั้นแทนที่จะสร้างเสื้อคลุมสำหรับ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);
แนวคิดทั้งสองข้างต้นสามารถนำไปใช้ในรูปแบบ OO ได้มากขึ้นโดยการสร้าง Class ที่ขยาย SqlCommand หรือ SqlConnection
หรือยังดีกว่า ( อื่น ๆส่วนที่ 3) คุณสามารถสร้างตัวจัดการเหตุการณ์สำหรับการเชื่อมต่อ 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
มา แต่ถ้าฉันปิดการใช้งาน Event Handler มันจะกลับ0
มา
เพื่อความสมบูรณ์นี่คือบางสิ่งที่ไม่สามารถใช้งานได้ (อย่างใดอย่างหนึ่งหรือไม่ได้ผล):
- การเข้าสู่ระบบทริกเกอร์ : ทริกเกอร์แม้ในขณะที่ทำงานในเซสชั่นเดียวกันและแม้ว่าการทำงานภายในทรานแซคชันที่เริ่มต้นอย่างชัดเจนยังคงเป็นกระบวนการย่อยและด้วยเหตุนี้การตั้งค่า (
SET
คำสั่งตารางชั่วคราวในท้องถิ่น ฯลฯ ) จุดสิ้นสุดของกระบวนการย่อยนั้น
- การเพิ่ม
SET ARITHABORT ON;
ไปยังจุดเริ่มต้นของแต่ละโพรซีเดอร์ที่เก็บไว้:
- สิ่งนี้ต้องการงานจำนวนมากสำหรับโครงการที่มีอยู่โดยเฉพาะอย่างยิ่งเมื่อจำนวนขั้นตอนการจัดเก็บเพิ่มขึ้น
- สิ่งนี้ไม่ได้ช่วยในการค้นหาเฉพาะกิจ