Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Använd SqlCommand för att köra Transact-SQL (T-SQL)-satser eller lagrade procedurer. Ett kommando behöver en öppen SqlConnection. Kassera kommandot efter användning och släng eventuell data reader innan du återanvänder anslutningen.
Exemplen i denna artikel förutsätter att en öppen SqlConnection med namnet connection är riktad mot AdventureWorks-exempeldatabasen.
C#-exemplen kräver using Microsoft.Data.SqlClient;. Exempel som använder SqlDbType, CommandBehavior eller using System.Data; kräver också CommandType.
För anslutningskonfiguration, autentisering och kryptering, se Anslutningssträngar och Kryptering och certifikatvalidering.
Välj en exekveringsmetod
Välj metoden som matchar det förväntade resultatet:
| Method | Använd när | Result |
|---|---|---|
| ExecuteNonQuery | Kommandot ändrar data eller schema. | Antalet rader som påverkas.
-1 kan inträffa när inget antal är tillgängligt, inklusive när SET NOCOUNT ON undertrycker antal. |
| ExecuteScalar | Du behöver ett värde. | Den första kolumnen i första raden, eller null när resultatet inte har några rader. En databas NULL returneras i form av Value. |
| ExecuteReader | Du behöver rader, flera resultatuppsättningar eller schema. | En SqlDataReader. |
| ExecuteXmlReader | Kommandot returnerar XML i den form som krävs av ExecuteXmlReader. |
En XmlReader. |
Varje metod har en uppgiftsbaserad asynkron motsvarighet. Skicka med a CancellationToken när anroparen behöver sluta vänta. För avbokning och timeout-beteende, se Asynkron programmering.
Utför ett textkommando
CommandType.Text används som standard. Placera satsen i CommandText och skicka värden genom parametrar:
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}");
}
För parametertyper, storlekar, nollvärden och riktningar, se Konfigurera parametrar. Sammanfoga inte opålitliga värden i CommandText.
Utföra en lagrad procedur
Sätt CommandType.StoredProcedure och använd namnet på schema-kvalificerad procedur:
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 stöder CommandType.Text och CommandType.StoredProcedure. Att ställa in CommandType.TableDirect utlöser ArgumentOutOfRangeException.
Kontrollera vad varje metod ger
Använd ExecuteScalar när du behöver ett värde:
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 returnerar null när resultatet inte har några rader och DBNull.Value när det första värdet är en databas NULL.
Använd ExecuteNonQuery för dataändrande instruktioner. Detta exempel rullar tillbaka sin ändring så att AdventureWorks förblir oförändrat:
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 undertrycker berörda radräkningar, så ExecuteNonQuery kan returnera -1 även när en sats ändrar data.
Använd ExecuteXmlReader för ett FOR XML resultat:
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());
Använd en lokal transaktion
När en anslutning har en aktiv lokal SqlTransaction tilldelar du den transaktionen till varje kommando som körs på anslutningen. Detta exempel rullar tillbaka sin ändring så att AdventureWorks förblir oförändrat:
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();
Ring Commit istället för Rollback bara när applikationen accepterar hela transaktionen. Ett kommando som inte refererar till den aktiva transaktionen kastar InvalidOperationException. Exekveringen misslyckas också om transaktionen tillhör en annan anslutning. För transaktionsgränser och rollback, se Lokala transaktioner.
Sätt en kommandotimeout
CommandTimeout begränsar kommandoexekvering och kumulativa nätverksläsväntetider i sekunder. Ett kommando använder anslutningens Command Timeout inställning när ett sådant är konfigurerat. Annars är standardläget 30 sekunder. Ett värde av 0 har ingen tidsgräns. Negativa värden ger upphov till ArgumentException.
När timeouten går ut kastar kommandot SqlException med Number inställt på -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 Begränsar anslutningsetablering och poolväntetider.
CommandTimeout börjar efter att kommandoexekveringen har börjat. För mer information, se Anslutningsalternativ.
Använd en begränsad timeout och en avbrottstoken tillsammans. Tidsgränsen sätter en gräns för databasoperationen. Att annullera tokenen kan återlämna kontrollen till anroparen innan timeouten går ut. Anta inte att avbokning och timeout ger samma undantag.
Återanvänd och förbered kommandon
Lägg till en parameter en gång och ändra dess värde efter att varje exekvering har slutförts:
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)}");
}
}
Ring Prepare bara när mätningarna motiverar det.
Prepare förbereder inte lagrade procedurer eller textkommandon utan parametrar. För parameteriserad text, ställ in komplett metadata såsom Size, Precision, och Scale på varje parameter innan du anropar Prepare.
Felsökningskommandon
Fånga SqlException kring databasåtgärden och inspektera dess Errors samling när servern returnerar mer än ett fel. För kommandofel, varningar och informationsmeddelanden, se Hantera fel och meddelanden.
Använd diagnostiska räknare, händelsekällspårning och SqlClients felsökningsguide när ett fel kräver mer kontext. Använd konfigurerbar återförsökslogik endast när det är säkert att upprepa kommandot.