Több parancs végrehajtása a SqlBatch segítségével

Használd a(z) SqlBatch egy rendezett objektumgyűjtemény SqlBatchCommand elküldésére egy nyitott SqlConnection-n keresztül. Minden batch parancsnak megvan a saját parancsszövege, parancstípusa, paraméterei, parancsviselkedése és az érintett sorok száma.

Használd SqlBatch , amikor egy alkalmazásnak különálló parancsai vannak, amelyeket együtt szeretne küldeni. Használj egy paraméterezett SqlCommand példányt, ha a munka egy utasításból vagy tárolt eljárásból áll. Nagy sorkészletek esetén használjon SqlBulkCopy elemet vagy táblázatértékű paramétert.

A cikkben szereplő példák feltételezik, hogy egy megnyitott, connection nevű SqlConnection az AdventureWorks mintaadatbázist célozza meg.

A C#-példákhoz using Microsoft.Data.SqlClient; szükséges. Azok a példák, amelyek SqlDbType-t vagy CommandBehavior-et használnak, using System.Data;-t is megkövetelnek. A(z) DbDataReader használó példákhoz using System.Data.Common; szükséges.

Verzió és platform támogatás

A példák a Microsoft.Data.SqlClient 7.1.0-t célozzák. Válassz egy csomagverziót és célkeretrendszert, amelyet a Microsoft.Data.SqlClient támogatási életciklusa támogat az alkalmazásod számára.

SqlBatch a DbBatch-ből származik modern .NET-en. A Microsoft.Data.SqlClient a .NET Framework és a .NET Standard 2.0 csomagösszetevőiben is elérhetővé teszi a SqlBatch-t. A nyilvános felület a célkeretrendszertől függően eltérhet, ezért fordítsd le az alkalmazást minden kiadott célhoz.

Köteg létrehozása

Hozz létre egy köteget egy nyitott kapcsolathoz, majd parancsokat adj hozzá végrehajtási sorrendben:

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());

CommandType.Text az alapértelmezett érték. Állíts be egy CommandType.StoredProcedure kötegparancsot egy tárolt eljáráshoz. A(z) CommandType.TableDirect beállítása ArgumentOutOfRangeException hibát dob.

Paraméterek hozzáadása a batch parancsokhoz

A paraméterek egy egyénhez SqlBatchCommandtartoznak. Ugyanaz a helyőrzőnév két batch parancsban nem ugyanazt az értéket használja:

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();

Állítsd be minden paraméter SQL típusát, valamint az alkalmazandó méretét, pontosságát és léptékét az adatbázis szerződéséből. További információ: Paraméterek konfigurálása.

Adatmódosító parancsok végrehajtása

Használd ExecuteNonQuery vagy ExecuteNonQueryAsync amikor a batch megváltoztatja az adatokat, és nincs szükséged eredménysorokra. A visszaadott érték az érintett sorok teljes száma, amikor a sorszámok rendelkezésre állnak. Végrehajtás után minden parancs RecordsAffected a saját darabszámát jelzi.

Ez a példa visszavonja a változtatásait:

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();

Több eredmény olvasása

Használd ExecuteReader vagy ExecuteReaderAsync, amikor bármelyik parancs sorokat ad vissza. Az olvasó az eredményeket a kötegelt parancsok sorrendjében mutatja be. Hívd NextResult vagy NextResultAsync amíg a visszatérési értéke false nem lesz.

Egy parancs nem hozhat létre sorkészletet, egyetlen sorkészletet vagy több sorkészletet. Ne feltételezd, hogy egy NextResult hívás egy SqlBatchCommand-nek felel meg.

Parancsviselkedés használata

Adjon át egy csomagszintű CommandBehavior elemet a(z) ExecuteReaderAsync vagy ExecuteReader számára, ha az olvasónak szekvenciális hozzáférésre van szüksége, vagy le kell zárnia a kapcsolatot:

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();
}

A kötegszintű túlterhelt változatok csak CommandBehavior.Default, CommandBehavior.SequentialAccess, CommandBehavior.CloseConnection és ezeknek az értékeknek a kombinációit fogadják el. Más érvényes értékek, például SingleRow, SchemaOnly és KeyInfo, ArgumentOutOfRangeException kivételt dobnak, ha egy kötegszintű overloadnak adják át. A batch-szintű viselkedési túlterhelések a Microsoft.Data.SqlClient 7.1-es verziójától kezdve érhetők el.

Állítsa be a(z) CommandBehavior beállítást egy adott parancshoz olyan lehetőségekhez, mint a SingleRow, SchemaOnly és KeyInfo. Használd a batch-szintű túlterhelést a(z) SequentialAccess és CloseConnection esetén.

Használjon tranzakciót

SqlBatch nem teszi a parancsait atomi műveletté. Használj explicit tranzakciót, amikor minden parancsot együtt kell véglegesíteni vagy vissza kell vonni. Ez a példa visszagörgetődik, így az AdventureWorks változatlan marad:

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();

Akkor hívd a(z) Commit elemet a(z) Rollback helyett, ha az alkalmazás elfogadja a teljes köteget. A tranzakciót a végrehajtás előtt rendeljük hozzá. A tranzakciónak és a batchnek ugyanazt a kapcsolatot kell használniuk. A SqlClient nem írja felül az aszinkron tranzakciós módszereket, tehát BeginTransactionAsync, CommitAsync és RollbackAsync szinkron módon fejeződik be. További információért lásd: Feladatalapú SQL tranzakciós módszerek használata.

Kezeld az időtúllépéseket, megszakításokat és hibákat

Állítsa be Timeout másodpercben a köteghez. A batch a kapcsolat Command Timeout beállítását használja, ha beállítasz egyet. Egyébként az alapértelmezett idő 30 másodperc. A(z) 0 értéknek nincs időkorlátja, és negatív értékek esetén a rendszer ArgumentException kivételt jelez. Adj át egy lemondási tokent egy aszinkron metódusnak, amikor a hívónak abba kell hagynia a várakozást, vagy hívd meg a(z) Cancel elemet. A lemondás csak a lehetőségekhez mérten történik. A művelet lehet, hogy a megszakítás hatálybalépése előtt befejeződik.

Ha a végrehajtás meghiúsul, kapd el a(z) SqlException kivételt, és vizsgáld meg az összes elemet annak Errors gyűjteményében. BatchCommand azonosítja a kapcsolódó SqlBatchCommand elemet, amikor ez az információ elérhető:

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}");
}

Az olvasó végrehajtása inkrementális. Egy későbbi batch parancsból származó hiba megjelenhet, amikor Read vagy NextResult előrehalad az adott parancsra, ezért dolgozd fel az olvasót a try blokk belsejében.

Ne naplózza az olyan paraméterértékeket, amelyek hitelesítő adatokat, tokeneket vagy érzékeny adatokat tartalmaznak. A hibamezőkkel és tájékoztató üzenetekkel kapcsolatban lásd: Hibák és üzenetek kezelése.