Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Używa się SqlCommand do wykonywania instrukcji języka Transact-SQL (T-SQL) lub procedur składowanych. Komenda wymaga otwartego SqlConnection. Zwolnij polecenie po użyciu i zwolnij obiekt readera przed ponownym użyciem połączenia.
Przykłady w tym artykule zakładają, że otwarte połączenie SqlConnection o nazwie connection wskazuje na przykładową bazę danych AdventureWorks.
Przykłady w języku C# wymagają using Microsoft.Data.SqlClient;. Przykłady używające SqlDbType, CommandType lub CommandBehavior również wymagają using System.Data;.
Aby dowiedzieć się o nawiązywaniu połączenia, uwierzytelnianiu i szyfrowaniu, zobacz Parametry połączenia oraz Szyfrowanie i sprawdzanie poprawności certyfikatu.
Wybierz metodę wykonania
Wybierz metodę odpowiadającą oczekiwanemu wynikowi:
| Metoda | Użyj, gdy | Result |
|---|---|---|
| ExecuteNonQuery | Polecenie zmienia dane lub schemat. | Liczba zmodyfikowanych wierszy.
-1 może wystąpić, gdy nie ma dostępnej liczby, w tym gdy SET NOCOUNT ON tłumi liczby. |
| ExecuteScalar | Potrzebujesz jednej wartości. | Pierwsza kolumna pierwszego wiersza lub null gdy wynik nie zawiera wierszy. Baza NULL danych jest zwracana jako Value. |
| ExecuteReader | Wiersze, wiele zestawów wyników lub schemat. | Element SqlDataReader. |
| ExecuteXmlReader | Polecenie zwraca XML w postaci wymaganej przez ExecuteXmlReader. |
Jeden XmlReader. |
Każda metoda ma asynchroniczny odpowiednik oparty na zadaniach. Przekaż CancellationToken, gdy dzwoniący musi przestać czekać. Informacje o zachowaniu anulowania i limicie czasu można znaleźć w sekcji Programowanie asynchroniczne.
Wykonaj polecenie tekstowe
Wartość domyślna to CommandType.Text. Umieść instrukcję w CommandText i przepuszczaj wartości przez parametry:
const string sql = """
SELECT ProductID, Name, ListPrice
FROM Production.Product
WHERE ProductSubcategoryID = @subcategoryId
ORDER BY ListPrice DESC;
""";
using var command = new SqlCommand(sql, connection);
command.Parameters.Add("@subcategoryId", SqlDbType.Int).Value = 2;
using SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
Console.WriteLine(
$"{reader.GetInt32(0)} | {reader.GetString(1)} | {reader.GetDecimal(2):C}");
}
Informacje o typach parametrów, rozmiarach, wartościach null i kierunkach znajdują się w Konfiguruj parametry. Nie łącz niezaufanych wartości w CommandText.
Wykonaj procedurę składowaną
Ustaw CommandType.StoredProcedure i użyj nazwy procedury kwalifikowanej przez schemat:
using var command = new SqlCommand(
"dbo.uspGetEmployeeManagers",
connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(
"@BusinessEntityID",
SqlDbType.Int).Value = 6;
using SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
Console.WriteLine(
$"{reader.GetString(2)} {reader.GetString(3)}");
}
Microsoft.Data.SqlClient obsługuje CommandType.Text i CommandType.StoredProcedure. Ustawienie CommandType.TableDirect powoduje ArgumentOutOfRangeException.
Sprawdź, co każda metoda zwraca
Używaj ExecuteScalar , gdy potrzebujesz jednej wartości:
using var command = new SqlCommand(
"SELECT COUNT(*) FROM Production.Product WHERE SellEndDate IS NULL;",
connection);
int currentProductCount = (int)command.ExecuteScalar()!;
Console.WriteLine($"Current products: {currentProductCount}");
ExecuteScalar zwraca null, gdy wynik nie zawiera wierszy, a ExecuteScalar zwraca DBNull.Value, gdy pierwsza wartość jest bazą danych NULL.
Użyj ExecuteNonQuery w instrukcjach zmieniających dane. Ten przykład cofa tę zmianę, więc AdventureWorks pozostaje bez zmian:
using SqlTransaction transaction = connection.BeginTransaction();
using var command = new SqlCommand("""
UPDATE Sales.SalesOrderHeader
SET Status = @status
WHERE SalesOrderID = @salesOrderId;
""", connection, transaction);
command.Parameters.Add("@status", SqlDbType.TinyInt).Value = 2;
command.Parameters.Add("@salesOrderId", SqlDbType.Int).Value = 43659;
int rowsAffected = command.ExecuteNonQuery();
Console.WriteLine($"Rows affected: {rowsAffected}");
transaction.Rollback();
SET NOCOUNT ON tłumi liczbę wierszy dotkniętych, więc ExecuteNonQuery może zwracać nawet -1 wtedy, gdy instrukcja zmienia dane.
Użyj ExecuteXmlReader, aby uzyskać efekt FOR XML:
using var command = new SqlCommand("""
SELECT TOP (3) ProductID, Name
FROM Production.Product
ORDER BY ProductID
FOR XML PATH('Product'), ROOT('Products');
""", connection);
using System.Xml.XmlReader reader = command.ExecuteXmlReader();
reader.MoveToContent();
Console.WriteLine(reader.ReadOuterXml());
Użyj transakcji lokalnej
Gdy połączenie ma aktywną lokalną transakcję SqlTransaction, przypisz tę transakcję do każdego polecenia wykonywanego na tym połączeniu. Ten przykład cofa tę zmianę, więc AdventureWorks pozostaje bez zmian:
using SqlTransaction transaction = connection.BeginTransaction();
using var command = new SqlCommand("""
UPDATE Sales.SalesOrderHeader
SET Status = @status
WHERE SalesOrderID = @salesOrderId;
""", connection, transaction);
command.Parameters.Add("@status", SqlDbType.TinyInt).Value = 2;
command.Parameters.Add("@salesOrderId", SqlDbType.Int).Value = 43659;
command.ExecuteNonQuery();
transaction.Rollback();
Wywołaj Commit zamiast Rollback tylko wtedy, gdy aplikacja zaakceptuje całą transakcję. Polecenie, które nie odwołuje się do aktywnej transakcji, powoduje zgłoszenie wyjątku InvalidOperationException. Wykonanie również nie udaje się, jeśli transakcja należy do innego połączenia. Dla granic transakcji i wycofywania, zobacz Transakcje lokalne.
Ustaw limit czasu polecenia
CommandTimeout ogranicza wykonywanie poleceń i skumulowane oczekiwania odczytu sieciowego w sekundach. Polecenie korzysta z ustawienia połączenia Command Timeout, gdy jest skonfigurowane. W przeciwnym razie domyślnie to 30 sekund. Wartość 0 nie ma limitu czasowego. Wartości ujemne powodują zgłoszenie wyjątku ArgumentException.
Gdy upłynie limit czasu, polecenie rzuca SqlException z ustawionym Number na -2:
using var command = new SqlCommand(
"WAITFOR DELAY '00:00:05';",
connection)
{
CommandTimeout = 1
};
try
{
command.ExecuteNonQuery();
}
catch (SqlException exception) when (exception.Number == -2)
{
Console.WriteLine("The command timed out.");
}
Connect Timeout Ogranicza oczekiwania na nawiązanie połączenia i oczekiwania na zasoby puli.
CommandTimeout rozpoczyna się po rozpoczęciu wykonywania polecenia. Więcej informacji można znaleźć w sekcji Opcje połączenia.
Używaj ograniczonego limitu czasu i tokena anulowania razem. Limit czasu operacji wyznacza limit dla operacji bazy danych. Anulowanie tokena może przywrócić kontrolę wywołującemu, zanim upłynie limit czasu. Nie zakładaj, że anulowanie i timeout dają ten sam wyjątek.
Ponowne wykorzystanie i przygotowanie poleceń
Dodaj parametr raz, a następnie zmieniaj jego wartość po zakończeniu każdego wykonania:
using var command = new SqlCommand("""
SELECT TOP (1) Name, ListPrice
FROM Production.Product
WHERE ProductSubcategoryID = @subcategoryId
ORDER BY ListPrice DESC;
""", connection);
SqlParameter subcategoryId = command.Parameters.Add(
"@subcategoryId",
SqlDbType.Int);
foreach (int id in new[] { 1, 2, 3 })
{
subcategoryId.Value = id;
using SqlDataReader reader = command.ExecuteReader();
if (reader.Read())
{
Console.WriteLine($"{id}: {reader.GetString(0)}");
}
}
Zadzwoń Prepare tylko wtedy, gdy pomiary to uzasadniają.
Prepare Nie przygotowuje procedur składowanych ani poleceń tekstowych bez parametrów. Dla tekstu parametryzowanego ustaw pełne metadane, takie jak Size, Scale i Prepare, dla każdego parametru przed wywołaniem Precision.
Polecenia rozwiązywania problemów
Przechwyć SqlException wokół operacji bazy danych i sprawdź jej kolekcję Errors, gdy serwer zwraca więcej niż jeden błąd. Informacje o błędach poleceń, ostrzeżeniach i komunikatach informacyjnych znajdziesz w Obsługa błędów i komunikatów.
Używaj liczników diagnostycznych, śledzenia źródła zdarzeń oraz przewodnika rozwiązywania problemów SqlClient, gdy błąd wymaga więcej kontekstu. Stosuj konfigurowalną logikę ponawiania tylko wtedy, gdy powtarzanie polecenia jest bezpieczne.