Approccio apparentemente preferito
Avevo l'impressione che quanto segue fosse già stato testato da altri, soprattutto sulla base di alcuni dei commenti. Ma i miei test dimostrano che questi due metodi funzionano davvero a livello di DB, anche quando ci si collega tramite .NET SqlClient
. Questi sono stati testati e verificati da altri.
A livello di server
È possibile impostare l' impostazione di configurazione del server delle opzioni utente su qualsiasi valore attualmente bit-saggio OR
con 64 (il valore per ARITHABORT
). Se non si utilizza OR ( |
) bit per bit ma si esegue invece un'assegnazione diretta ( =
), verranno eliminate tutte le altre opzioni esistenti già abilitate.
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
A livello di database
Questo può essere impostato per database tramite 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;
Approcci alternativi
La non buona notizia è che ho fatto molte ricerche su questo argomento, solo per scoprire che nel corso degli anni molti altri hanno fatto molte ricerche su questo argomento e non c'è modo di configurare il comportamento di SqlClient
. Una parte della documentazione MSDN implica che può essere eseguita tramite ConnectionString, ma non esistono parole chiave che consentano di modificare queste impostazioni. Un altro documento implica che può essere modificato tramite la configurazione della rete client / Configuration Manager, ma neanche questo sembra possibile. Quindi, e piuttosto sfortunatamente, dovrai eseguirlo SET ARITHABORT ON;
manualmente. Ecco alcuni modi per considerare:
SE stai utilizzando Entity Framework 6 (o più recente), puoi provare:
Usa Database.ExecuteSqlCommand : context.Database.ExecuteSqlCommand("SET ARITHABORT ON;");
idealmente dovrebbe essere eseguito una volta, dopo aver aperto la connessione DB, e non per ogni query.
Crea un intercettore tramite:
Questo vi permetterà di modificare il codice SQL prima che sia eseguito, nel qual caso si può semplicemente premettere ad essa: SET ARITHABORT ON;
. Il rovescio della medaglia qui è che sarà per ogni query, a meno che non memorizzi una variabile locale per catturare lo stato del fatto che sia stata eseguita o meno e verificarla ogni volta (che in realtà non è molto lavoro extra, ma usando ExecuteSqlCommand
è probabilmente più facile).
Ognuno di questi ti permetterà di gestirlo in un punto senza cambiare alcun codice esistente.
Inoltre , è possibile creare un metodo wrapper che faccia questo, simile a:
public static SqlDataReader ExecuteReaderWithSetting(SqlCommand CommandToExec)
{
CommandToExec.CommandText = "SET ARITHABORT ON;\n" + CommandToExec.CommandText;
return CommandToExec.ExecuteReader();
}
e poi basta cambiare i _Reader = _Command.ExecuteReader();
riferimenti attuali per essere _Reader = ExecuteReaderWithSetting(_Command);
.
In questo modo è anche possibile gestire le impostazioni in un'unica posizione, richiedendo al contempo modifiche minime e semplicistiche al codice che possono essere eseguite principalmente tramite Trova e sostituisci.
Meglio ancora ( Else Part 2), poiché si tratta di un'impostazione a livello di connessione, non è necessario eseguirla per ogni chiamata SqlCommand.Execute __ (). Quindi, invece di creare un wrapper per ExecuteReader()
, crea un wrapper per 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;
}
E poi basta sostituire i _Connection.Open();
riferimenti esistenti per essere OpenAndSetArithAbort(_Connection);
.
Entrambe le idee di cui sopra possono essere implementate in più stile OO creando una classe che estende SqlCommand o SqlConnection.
O ancora meglio ( Else Parte 3), è possibile creare un gestore di eventi per la connessione StateChange e lo hanno impostato la proprietà quando cambia la connessione da Closed
a Open
come segue:
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();
}
}
}
Con quello in atto, devi solo aggiungere quanto segue in ogni luogo in cui crei SqlConnection
un'istanza:
_Connection.StateChange += new StateChangeEventHandler(OnStateChange);
Non sono necessarie modifiche al codice esistente. Ho appena provato questo metodo in una piccola app per console, testando stampando il risultato di SELECT SESSIONPROPERTY('ARITHABORT');
. Ritorna 1
, ma se disabilito il gestore eventi, ritorna 0
.
Per completezza, ecco alcune cose che non funzionano (né affatto né altrettanto efficacemente):
- Trigger di accesso : i trigger, anche durante l'esecuzione nella stessa sessione, e anche se eseguiti all'interno di una transazione avviata in modo esplicito, sono ancora un processo secondario e quindi le sue impostazioni (
SET
comandi, tabelle temporanee locali, ecc.) Sono locali e non sopravvivono la fine di quel sottoprocesso.
- Aggiunta
SET ARITHABORT ON;
all'inizio di ogni procedura memorizzata:
- ciò richiede molto lavoro per i progetti esistenti, specialmente all'aumentare del numero di procedure memorizzate
- questo non aiuta le query ad hoc