Abordagem aparentemente preferida
Fiquei com a impressão de que o seguinte já havia sido testado por outras pessoas, especialmente com base em alguns dos comentários. Mas meus testes mostram que esses dois métodos realmente funcionam no nível do banco de dados, mesmo ao conectar via .NET SqlClient
. Estes foram testados e verificados por outros.
Em todo o servidor
É possível definir a configuração do servidor de opções do usuário para o que for atualmente definido em bits OR
com 64 (o valor para ARITHABORT
). Se você não usar o OR (em bits |
), mas fizer uma atribuição direta ( =
), eliminará todas as outras opções existentes já ativadas.
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
No nível do banco de dados
Isso pode ser definido por banco de dados via 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;
Abordagens alternativas
A notícia não tão boa é que eu pesquisei bastante esse tópico, apenas para descobrir que, ao longo dos anos, muitos outros pesquisaram muito sobre esse assunto, e não há como configurar o comportamento de SqlClient
. Algumas documentações do MSDN indicam que isso pode ser feito por meio de um ConnectionString, mas não há palavras-chave que permitam alterar essas configurações. Outro documento implica que ele pode ser alterado via Gerenciador de Configuração / Configuração de Rede do Cliente, mas isso também não parece possível. Portanto, e, infelizmente, você precisará executar SET ARITHABORT ON;
manualmente. Aqui estão algumas maneiras de considerar:
Se você estiver usando o Entity Framework 6 (ou mais recente), você pode tentar:
Use Database.ExecuteSqlCommand : context.Database.ExecuteSqlCommand("SET ARITHABORT ON;");
Idealmente, isso seria executado uma vez, após abrir a conexão com o banco de dados, e não por cada consulta.
Crie um interceptor via:
Isso permitirá que você modifique o SQL antes de ser executado, caso em que você pode simplesmente prefixo com: SET ARITHABORT ON;
. A desvantagem aqui é que será por cada consulta, a menos que você armazene uma variável local para capturar o estado de se ela foi executada ou não e teste para cada vez (o que realmente não é muito trabalho extra, mas usar ExecuteSqlCommand
é provavelmente mais fácil).
Qualquer um deles permitirá que você lide com isso em um único local sem alterar nenhum código existente.
ELSE , você pode criar um método de wrapper que faça isso, semelhante a:
public static SqlDataReader ExecuteReaderWithSetting(SqlCommand CommandToExec)
{
CommandToExec.CommandText = "SET ARITHABORT ON;\n" + CommandToExec.CommandText;
return CommandToExec.ExecuteReader();
}
e depois basta alterar as _Reader = _Command.ExecuteReader();
referências atuais _Reader = ExecuteReaderWithSetting(_Command);
.
Isso também permite que a configuração seja manipulada em um único local, exigindo apenas alterações de código mínimas e simplistas que podem ser feitas principalmente via Localizar e substituir.
Melhor ainda ( outra parte 2), como essa é uma configuração de nível de conexão, ela não precisa ser executada a cada chamada SqlCommand.Execute __ (). Portanto, em vez de criar um wrapper para ExecuteReader()
, crie um wrapper para 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 então apenas substitua as _Connection.Open();
referências existentes OpenAndSetArithAbort(_Connection);
.
Ambas as idéias acima podem ser implementadas em mais estilos OO, criando uma classe que estenda SqlCommand ou SqlConnection.
Ou melhor ainda ( outra parte 3), você pode criar um manipulador de eventos para o Connection StateChange e definir a propriedade quando a conexão mudar de Closed
para da Open
seguinte maneira:
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();
}
}
}
Com isso em vigor, você só precisará adicionar o seguinte a cada local em que criar uma SqlConnection
instância:
_Connection.StateChange += new StateChangeEventHandler(OnStateChange);
Nenhuma alteração no código existente é necessária. Eu apenas tentei esse método em um aplicativo de console pequeno, testando imprimindo o resultado de SELECT SESSIONPROPERTY('ARITHABORT');
. Ele retorna 1
, mas se eu desativar o Manipulador de Eventos, ele retornará 0
.
Por uma questão de completude, eis algumas coisas que não funcionam (ou não são tão eficazes):
- Disparadores de logon : Os disparadores, mesmo durante a execução na mesma sessão, e mesmo sendo executados em uma transação explicitamente iniciada, ainda são um subprocesso e, portanto, suas configurações (
SET
comandos, tabelas temporárias locais, etc.) são locais e não sobrevivem. o fim desse subprocesso.
- Adicionando
SET ARITHABORT ON;
ao início de cada procedimento armazenado:
- isso requer muito trabalho para projetos existentes, principalmente porque o número de procedimentos armazenados aumenta
- isso não ajuda a consultas ad hoc