Ligue-se a uma fonte de dados com a Microsoft. Data.SqlClient

SqlConnectionrepresenta uma ligação lógica ao SQL Server, SQL do Azure ou outro endpoint compatível com SQL Server suportado. Ao abrir o objeto, é obtida uma ligação física do pool de ligações quando houver uma disponível. Fechar ou descartá-lo devolve essa ligação física ao pool.

Utilize objetos SqlConnection de curta duração para unidades de trabalho. Não mantenhas uma ligação global aberta para a aplicação.

Construir a configuração da ligação

Carregue uma cadeia de ligação a partir do sistema de configuração da aplicação. Use SqlConnectionStringBuilder quando o código precisa de validar ou adicionar definições:

string configuredConnectionString =
    configuration.GetConnectionString("Orders")
    ?? throw new InvalidOperationException(
        "Connection string 'Orders' wasn't configured.");

var builder = new SqlConnectionStringBuilder(configuredConnectionString)
{
    ApplicationName = "Orders.Api",
};

Crie o SqlConnection a partir de builder.ConnectionString. Não concatenes a entrada do utilizador na string. Para padrões de autenticação, armazenamento seguro e sintaxe, veja Strings de Conexão.

Abrir e fechar conexões

Chama Open código síncrono ou OpenAsync código assíncrono. Abrir uma nova ligação lógica para cada operação independente:

public static async Task<string?> LoadOrderStatusAsync(
    string connectionString,
    int orderId,
    CancellationToken cancellationToken)
{
    await using var connection = new SqlConnection(connectionString);
    await connection.OpenAsync(cancellationToken);

    const string sql = """
        SELECT Status
        FROM Sales.Orders
        WHERE OrderId = @orderId;
        """;

    using var command =
        new SqlCommand(sql, connection) { CommandTimeout = 30 };
    command.Parameters.Add(
        new SqlParameter("@orderId", SqlDbType.Int) { Value = orderId });

    object? value =
        await command.ExecuteScalarAsync(cancellationToken);
    return value is null or DBNull ? null : (string)value;
}

A await using instrução elimina a ligação em caso de sucesso, erro ou cancelamento. Com o pooling ativado, a eliminação normalmente repõe e devolve a conexão física em vez de fechar o respetivo socket de rede.

Elimine os leitores e os comandos antes da conexão a que pertencem. Não dependa de recolha de lixo ou de um finalizador para devolver ligações à piscina.

Usar APIs assíncronas

Utilize chamadas assíncronas para trabalho de bases de dados ligadas à rede em servidores web, serviços, interfaces de utilizador e trabalhadores:

  • OpenAsync(cancellationToken)
  • ExecuteNonQueryAsync(cancellationToken)
  • ExecuteReaderAsync(cancellationToken)
  • ExecuteScalarAsync(cancellationToken)
  • ReadAsync(cancellationToken)

Não precisas de Asynchronous Processing=true. Microsoft. Data.SqlClient 4.0 e versões posteriores não suportam essa palavra-chave de cadeia de ligação.

Não inicie outra operação numa ligação, comando ou leitor antes de a operação assíncrona atual terminar.

Aplicar cancelamento e tempos limite

Passe o CancellationToken do autor da chamada em todas as chamadas assíncronas à base de dados. O cancelamento pede ao prestador que pare o trabalho pendente, mas a conclusão não é garantida de ser imediata. Continue a utilizar tempos limite limitados para a ligação e para os comandos.

Estes controlos têm escopos separados:

Controlo Scope
Connect Timeout Estabelecimento de ligação ou espera de uma ligação agrupada
SqlCommand.CommandTimeout Execução de um comando
CancellationToken Cancelamento solicitado pelo chamador de uma operação assíncrona

A expiração do tempo limite ou o cancelamento não provam que o servidor anulou uma operação. Use uma transação quando várias alterações tiverem de ser confirmadas ou revertidas como uma única unidade, e tome decisões de repetição com base na idempotência da operação e no resultado da transação.

Compreender o estado da ligação

A propriedade State devolve um instantâneo da enumeração ConnectionState.

Estado Meaning
Closed A ligação lógica não está aberta.
Connecting Está em curso uma operação aberta.
Open A ligação lógica está aberta.

Não uses State como verificação de saúde antes de cada comando. A rede pode falhar após qualquer verificação. Execute a operação e trate da exceção resultante.

O controlador normalmente indica transições de fechado para aberto e de aberto para fechado. Não contes com a observação de Executing, Fetching ou Broken como fases do ciclo de vida da aplicação.

O StateChange evento relata transições de estados. O evento InfoMessage comunica mensagens informativas e avisos emitidos pelo servidor que não dão origem a exceções. Use estes eventos para diagnósticos, não para coordenar trabalhos simultâneos.

Não partilhem uma ligação ao mesmo tempo

SqlConnection, SqlCommand, SqlDataReader, e SqlTransaction não suportam o uso simultâneo por múltiplas threads. Atribua a cada operação concorrente a sua própria ligação e permita que o agrupamento de ligações reutilize as ligações físicas.

Múltiplos Conjuntos de Resultados Ativos (MARS) permitem múltiplos lotes ativos numa única ligação em cenários suportados. Não torna os objetos SqlClient seguros em ambientes multithread e adiciona regras relativas à sessão e às transações. Deixa-o desativado, a menos que uma operação precise especificamente.

Não registar um tipo genérico aberto SqlConnection como singleton na injeção de dependências. Regista a cadeia de ligação, um objeto de opções imutável ou uma função de fábrica que cria uma nova ligação.

Usar as transações de forma deliberada

Uma transação local pertence à sua ligação. Cada comando na transação deve usar essa ligação e definir a sua Transaction propriedade.

await using var connection = new SqlConnection(connectionString);
await connection.OpenAsync(cancellationToken);

await using SqlTransaction transaction =
    (SqlTransaction)await connection.BeginTransactionAsync(cancellationToken);

using var command = new SqlCommand(sql, connection, transaction);
command.Parameters.Add(
    new SqlParameter("@value", SqlDbType.Int) { Value = value });
await command.ExecuteNonQueryAsync(cancellationToken);

await transaction.CommitAsync(cancellationToken);

Se a operação falhar antes de CommitAsync, a eliminação da transação faz com que esta seja anulada. Mantenha as transações curtas. Não faça chamadas de rede, interação com utilizadores ou cálculos não relacionados enquanto uma transação na base de dados tem bloqueios.

Quando System.Transactions.Transaction.Current está ativa, Open e OpenAsync aderem automaticamente por predefinição. Defina Enlist=false apenas quando a operação tiver de ficar fora da transação ambiente.

Medir uma ligação lógica

Defina StatisticsEnabled como true para recolher estatísticas do fornecedor para um objeto SqlConnection:

await using var connection = new SqlConnection(connectionString)
{
    StatisticsEnabled = true,
};

await connection.OpenAsync(cancellationToken);
connection.ResetStatistics();

using var command = new SqlCommand(sql, connection);
await command.ExecuteNonQueryAsync(cancellationToken);

System.Collections.IDictionary statistics =
    connection.RetrieveStatistics();
long roundTrips =
    Convert.ToInt64(statistics["ServerRoundtrips"]);

RetrieveStatistics retorna um snapshot. ResetStatistics Inicia um novo limite de medição. Defina StatisticsEnabled=false para deixar de recolher; os valores recolhidos até ao momento continuam disponíveis. As estatísticas são associadas a cada objeto de ligação e introduzem sobrecarga, por isso ative-as para diagnósticos direcionados em vez de as ativar para todos os pedidos em produção.

Para medições de conjuntos e ligações ao nível de todo o processo, utilize os contadores de diagnóstico do SqlClient.

Lidar com falhas de conexão

Agarre SqlException numa fronteira que possa registar, traduzir ou tentar novamente a falha. Recorde:

  • Number
  • State
  • Class
  • ClientConnectionId
  • O nome da operação e os identificadores configurados do servidor e da base de dados

Não registe a cadeia de ligação, a palavra-passe, o segredo do cliente ou o token de acesso.

Elimine uma conexão interrompida. O pool remove ligações físicas inválidas quando as deteta. Se uma credencial, token, certificado, destino DNS ou servidor tiver sido alterado, corrija a configuração antes de voltar a tentar.

Utilize lógica de repetição limitada apenas para falhas transitórias. A nova tentativa de abertura inicial, a recuperação de uma ligação inativa e a nova tentativa de comando são mecanismos diferentes. Consulte Lógica de repetição configurável.