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żyj SqlBatch do przesyłania uporządkowanej kolekcji obiektów SqlBatchCommand przez jedno otwarte SqlConnection. Każde polecenie wsadowe ma własny tekst polecenia, typ polecenia, parametry, zachowanie polecenia oraz wynik dotyczący liczby wierszy, których dotyczyło polecenie.
Używaj SqlBatch , gdy aplikacja ma odrębne polecenia, które chce wysłać razem. Używaj jednego parametryzowanego SqlCommand, gdy operacja jest jedną instrukcją lub procedurą przechowywaną. Użyj SqlBulkCopy lub parametru tabelowego dla dużych zestawów wierszy.
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, które używają SqlDbType lub CommandBehavior również wymagają using System.Data;. Przykłady, które używają DbDataReader , wymagają using System.Data.Common;.
Wsparcie dla wersji i platformy
Przykłady są skierowane do Microsoft.Data.SqlClient 7.1.0. Wybierz wersję pakietu i platformę docelową obsługiwane przez cykl pomocy technicznej Microsoft.Data.SqlClient dla Twojej aplikacji.
SqlBatch pochodzi od DbBatch w nowoczesnym środowisku .NET. Microsoft.Data.SqlClient udostępnia również SqlBatch w zasobach pakietu .NET Framework oraz .NET Standard 2.0. Publiczny interfejs API może się różnić w zależności od platformy docelowej, więc kompiluj aplikację dla każdej platformy docelowej, którą dostarczasz.
Utwórz partię
Utwórz batch dla otwartego połączenia, a następnie dodaj polecenia w kolejności wykonywania:
using var batch = new SqlBatch(connection);
batch.BatchCommands.Add(new SqlBatchCommand("""
SELECT TOP (3) ProductID, Name
FROM Production.Product
ORDER BY ProductID;
"""));
batch.BatchCommands.Add(new SqlBatchCommand("""
SELECT TOP (3) SalesOrderID, OrderDate
FROM Sales.SalesOrderHeader
ORDER BY SalesOrderID;
"""));
using DbDataReader reader = batch.ExecuteReader();
do
{
while (reader.Read())
{
Console.WriteLine($"{reader.GetValue(0)} | {reader.GetValue(1)}");
}
}
while (reader.NextResult());
Wartość domyślna to CommandType.Text. Ustaw polecenie batch na CommandType.StoredProcedure dla procedury przechowywanej. Ustawienie CommandType.TableDirect powoduje ArgumentOutOfRangeException.
Dodaj parametry do poleceń wsadowych
Parametry należą do osoby SqlBatchCommand. Ta sama nazwa symbolu zastępczego w dwóch poleceniach batch nie ma wspólnej wartości:
using var batch = new SqlBatch(connection);
var products = new SqlBatchCommand("""
SELECT ProductID, Name
FROM Production.Product
WHERE ProductSubcategoryID = @id
ORDER BY ProductID;
""");
products.Parameters.Add("@id", SqlDbType.Int).Value = 2;
batch.BatchCommands.Add(products);
var orders = new SqlBatchCommand("""
SELECT SalesOrderID, OrderDate
FROM Sales.SalesOrderHeader
WHERE SalesPersonID = @id
ORDER BY SalesOrderID;
""");
orders.Parameters.Add("@id", SqlDbType.Int).Value = 279;
batch.BatchCommands.Add(orders);
using DbDataReader reader = batch.ExecuteReader();
Ustaw typ SQL każdego parametru oraz odpowiedni rozmiar, precyzję i skalę na podstawie kontraktu bazy danych. Aby uzyskać więcej informacji, zobacz sekcję Konfigurowanie narzędzia integracji.
Wykonaj polecenia zmieniające dane
Używaj ExecuteNonQuery lub ExecuteNonQueryAsync, gdy partia zmienia dane i nie potrzebujesz wierszy wyników. Wartość zwracana to łączna liczba wierszy, na które operacja wpłynęła, gdy liczba wierszy jest dostępna. Po wykonaniu każde polecenie RecordsAffected raportuje własną liczbę.
Ten przykład cofa własne zmiany:
using SqlTransaction transaction = connection.BeginTransaction();
using var batch = new SqlBatch(connection, transaction);
var firstUpdate = new SqlBatchCommand("""
UPDATE Sales.SalesOrderHeader
SET Status = @status
WHERE SalesOrderID = @salesOrderId;
""");
firstUpdate.Parameters.Add("@status", SqlDbType.TinyInt).Value = 2;
firstUpdate.Parameters.Add("@salesOrderId", SqlDbType.Int).Value = 43659;
batch.BatchCommands.Add(firstUpdate);
var secondUpdate = new SqlBatchCommand("""
UPDATE Sales.SalesOrderHeader
SET Status = @status
WHERE SalesOrderID = @salesOrderId;
""");
secondUpdate.Parameters.Add("@status", SqlDbType.TinyInt).Value = 2;
secondUpdate.Parameters.Add("@salesOrderId", SqlDbType.Int).Value = 43660;
batch.BatchCommands.Add(secondUpdate);
int totalRows = batch.ExecuteNonQuery();
Console.WriteLine($"Total rows: {totalRows}");
foreach (SqlBatchCommand command in batch.BatchCommands)
{
Console.WriteLine(command.RecordsAffected);
}
transaction.Rollback();
Wyświetl wiele wyników
Używaj ExecuteReader lub ExecuteReaderAsync gdy jakiekolwiek polecenie zwraca wiersze. Odczytnik udostępnia wyniki w kolejności poleceń wsadowych. Zadzwoń NextResult lub NextResultAsync do momentu, aż zwróci false.
Polecenie może wygenerować żadnego zestawu wierszy, jeden zestaw wierszy lub wiele zestawów wierszy. Nie zakładaj, że jedno NextResult wywołanie odwzorowuje się na jedno SqlBatchCommand.
Użyj zachowania polecenia
Przekaż element CommandBehavior na poziomie partii do ExecuteReader lub ExecuteReaderAsync, gdy czytnik potrzebuje dostępu sekwencyjnego lub musi zamknąć połączenie:
using var batch = new SqlBatch(connection);
batch.BatchCommands.Add(new SqlBatchCommand("""
SELECT DocumentSummary
FROM Production.Document
WHERE DocumentSummary IS NOT NULL;
"""));
using DbDataReader reader =
batch.ExecuteReader(CommandBehavior.SequentialAccess);
char[] buffer = new char[4096];
while (reader.Read())
{
using TextReader summary = reader.GetTextReader(0);
int count;
while ((count = summary.Read(buffer, 0, buffer.Length)) > 0)
{
Console.Out.Write(buffer, 0, count);
}
Console.WriteLine();
}
Przeciążenia na poziomie partii akceptują tylko CommandBehavior.Default, CommandBehavior.SequentialAccess, , CommandBehavior.CloseConnectionoraz kombinacje tych wartości. Inne poprawne wartości, takie jak SingleRow, KeyInfo i ArgumentOutOfRangeException, powodują zgłoszenie SchemaOnly po przekazaniu do przeciążenia na poziomie partii. Przeciążenia zachowań na poziomie wsadowym są dostępne już od Microsoft.Data.SqlClient 7.1.
Ustaw CommandBehavior dla pojedynczego polecenia dla opcji takich jak SingleRow, SchemaOnly i KeyInfo. Użyj przeciążenia na poziomie wsadu dla SequentialAccess i CloseConnection.
Skorzystaj z transakcji
SqlBatch nie wykonuje swoich poleceń atomowo. Użyj jawnej transakcji, gdy wszystkie polecenia muszą zostać zatwierdzone lub wycofane razem. Ten przykład powoduje wycofanie zmian, więc AdventureWorks pozostaje bez zmian:
using SqlTransaction transaction = connection.BeginTransaction();
using var batch = new SqlBatch(connection, transaction);
batch.BatchCommands.Add(new SqlBatchCommand("""
UPDATE Sales.SalesOrderHeader
SET Status = 2
WHERE SalesOrderID = 43659;
"""));
batch.BatchCommands.Add(new SqlBatchCommand("""
UPDATE Sales.SalesOrderHeader
SET Status = 2
WHERE SalesOrderID = 43660;
"""));
batch.ExecuteNonQuery();
transaction.Rollback();
Wywołaj Commit zamiast Rollback tylko wtedy, gdy aplikacja zaakceptuje pełną partię. Przydziel transakcję przed wykonaniem. Transakcja i batch muszą korzystać z tego samego połączenia. SqlClient nie nadpisuje asynchronicznych metod transakcji, więc BeginTransactionAsync, CommitAsync i RollbackAsync są wykonywane synchronicznie. Więcej informacji można znaleźć w artykule Korzystanie z metod transakcji SQL opartych na zadaniach.
Obsługa limitów czasu, anulowania i błędów
Ustaw Timeout w sekundach dla przetwarzania wsadowego. Batch używa ustawienia połączenia Command Timeout, jeśli je skonfigurujesz. W przeciwnym razie domyślnie to 30 sekund. Wartość 0 nie ma limitu czasu, a wartości ujemne rzucają ArgumentException. Przekaż token anulowania do asynchronicznej metody wykonania, gdy wywołujący musi przestać czekać, lub wywołaj Cancel. Anulowanie jest realizowane w miarę możliwości. Operacja może zakończyć się, zanim anulowanie zostanie zastosowane.
Gdy wykonanie się nie powiedzie, przechwyć SqlException i sprawdź każdy element w kolekcji Errors.
BatchCommand identyfikuje powiązane SqlBatchCommand, gdy te informacje są dostępne:
using var batch = new SqlBatch(connection);
batch.BatchCommands.Add(new SqlBatchCommand(
"SELECT TOP (1) ProductID FROM Production.Product;"));
batch.BatchCommands.Add(new SqlBatchCommand("SELECT 1 / 0;"));
try
{
using DbDataReader reader = batch.ExecuteReader();
do
{
while (reader.Read())
{
Console.WriteLine(reader.GetValue(0));
}
}
while (reader.NextResult());
}
catch (SqlException exception)
{
Console.WriteLine(
exception.BatchCommand is null
? "The batch failed."
: $"Failed command: {exception.BatchCommand.CommandText}");
}
Wykonywanie przez czytnik jest przyrostowe. Błąd z późniejszego polecenia wsadowego może pojawić się, gdy Read lub NextResult przejdzie do tego polecenia, więc przetwarzaj czytnik wewnątrz bloku try.
Nie rejestruj wartości parametrów zawierających poświadczenia, tokeny lub wrażliwe dane. Informacje o polach błędów i komunikatach informacyjnych można znaleźć w sekcji Obsługa błędów i komunikatów.