Parancs végrehajtása

Használd a(z) SqlCommand elemet Transact-SQL (T-SQL) utasítások vagy tárolt eljárások végrehajtására. Egy parancshoz nyitott SqlConnection szükséges. A parancsot használat után dobd el, és a reader objektumot a kapcsolat újrahasználata előtt dobd el.

A cikkben szereplő példák feltételezik, hogy egy nyitott, 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, CommandType vagy CommandBehavior elemet használnak, szintén megkövetelik a(z) using System.Data; elemet.

A kapcsolat beállításáról, hitelesítésről és titkosításról lásd: kapcsolati karakterláncok és Titkosítás és tanúsítvány ellenőrzés.

Válasszon végrehajtási módot

Válaszd ki azt a módszert, amely megfelel a várt eredménynek:

Method Használja amikor Result
ExecuteNonQuery A parancs megváltoztatja az adatokat vagy sémát. Az érintett sorok száma. -1 előfordulhat, ha nincs elérhető darabszám, beleértve azt is, amikor a SET NOCOUNT ON elnyomja a darabszámokat.
ExecuteScalar Szükséged van egy értékre. Az első sor első oszlopa, vagy null, ha az eredménynek nincsenek sorai. Egy adatbázis NULLValueként jelenik meg.
ExecuteReader Sorokra, több eredményhalmazra vagy sémára van szükséged. Egy SqlDataReader.
ExecuteXmlReader A parancs az XML-t a ExecuteXmlReader által megkövetelt alakban adja vissza. Egy XmlReader.

Minden módszernek van feladat-alapú aszinkron megfelelője. Adj át egy CancellationToken-t, amikor a hívó félnek nem kell tovább várnia. A törlés és időtúllépés viselkedéséről lásd: Aszinkron programozás.

Szöveges parancs végrehajtása

CommandType.Text az alapértelmezett érték. Helyezze az állítást a(z) CommandText elembe, és adja át az értékeket paramétereken keresztül:

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

A paramétertípusokkal, méretekkel, nullértékekkel és irányokkal kapcsolatban lásd a következőt: Paraméterek konfigurálása. Ne fűzd össze a megbízhatatlan értékeket a(z) CommandText elemmel.

Tárolt eljárás végrehajtása

Állítsuk CommandType.StoredProcedure be és használjuk a sémához kötött eljárás nevét:

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 támogatja CommandType.Text és CommandType.StoredProcedure. A(z) CommandType.TableDirect beállítása a következőt dobja: ArgumentOutOfRangeException.

Nézd meg, mit ad vissza az egyes módszerek

Használd ExecuteScalar , amikor szükséged van egy értékre:

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 null értéket ad vissza, ha az eredménynek nincs sora, és DBNull.Value értéket, amikor az első érték adatbázis-NULL.

Használja a(z) ExecuteNonQuery elemet adatmódosító utasításokhoz. Ez a példa visszafordítja a változást, így az AdventureWorks változatlan marad:

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 elnyomja az érintett sorok számát, így ExecuteNonQuery vissza is térhet -1 , ha egy utasítás megváltoztatja az adatokat.

A(z) FOR XML eredményhez használja a(z) ExecuteXmlReader elemet:

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

Használj helyi tranzakciót

Ha egy csatlakozásnak aktív helyi SqlTransaction tranzakciója van, rendeljük hozzá ezt a tranzakciót minden, a csatlakozáson végrehajtott parancshoz. Ez a példa visszafordítja a változást, így az AdventureWorks változatlan marad:

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

Csak akkor hívd meg a(z) Commit elemet a(z) Rollback helyett, ha az alkalmazás elfogadja a teljes tranzakciót. Egy parancs, amely nem hivatkozik az aktív tranzakcióra, InvalidOperationException kivételt vált ki. A végrehajtás akkor is meghiúsul, ha a tranzakció egy másik kapcsolathoz tartozik. A tranzakcióhatárokról és a visszagörgetésről lásd: Helyi tranzakciók.

Állítsd be a parancs időkorlátját

A CommandTimeout másodpercekben korlátozza a parancsvégrehajtást és a hálózati olvasás összesített várakozását. Egy parancs a kapcsolat Command Timeout beállítását használja, ha az konfigurálva van. Egyébként az alapértelmezett idő 30 másodperc. Az értéknek 0 nincs időkorlátja. A negatív értékek ArgumentException kivételt eredményeznek.

Amikor az időtúllépés lejár, a parancs SqlException kivételt dob, ahol a(z) Number értéke -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 korlátozza a csatlakozás létrehozását és a kapcsolatkészletben való várakozást. CommandTimeout a parancs végrehajtásának kezdetekor indul. További információkért lásd a Kapcsolódási beállítások című részt.

Használj egy véges időtúllépést és egy megszakítási tokent együtt. Az időtúllépés korlátot szab az adatbázis-műveletre. A token törlése visszaadhatja az irányítást a hívónak az időtúllépés lejárása előtt. Ne feltételezd, hogy a törlés és az időtúllépés ugyanazt a kivételt eredményezi.

Parancsok újrafelhasználása és előkészítése

Egyszer adj hozzá egy paramétert, majd minden végrehajtás után változtasd meg az értékét:

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

Csak akkor hívj Prepare , ha a mérések indokolják. Prepare nem előkészít tárolt eljárásokat vagy szöveges parancsokat paraméterek nélkül. Paraméterezett szöveghez állítsunk be teljes metaadatokat, például Size, Scale és Prepare minden paraméterre, mielőtt hívnánk Precision.

Hibaelhárítási parancsok

Fogd el a(z) SqlException kivételt az adatbázis-művelet körül, és vizsgáld meg annak Errors gyűjteményét, ha a szerver több hibát is visszaad. Parancshibák, figyelmeztetések és tájékoztató üzenetek esetén lásd: Hibák és üzenetek kezelése.

Használj diagnosztikai számlálókat, eseményforrás követést és a SqlClient hibaelhárítási útmutatót , ha egy hiba több kontextust igényel. A konfigurálható újrapróbálkozási logikát csak akkor alkalmazd, ha a parancs ismétlése biztonságos.