Komut yürütme

Transact-SQL (T-SQL) ifadelerini veya depolanmış prosedürleri çalıştırmak için kullanılır SqlCommand . Bir komut açık SqlConnection gerektirir. Komutu kullandıktan sonra atın ve bağlantıyı tekrar kullanmadan önce herhangi bir reader nesnesini atın.

Bu makaledeki örnekler, connection adlı açık bir SqlConnection öğesinin AdventureWorks örnek veritabanını hedeflediğini varsaymaktadır.

C# örnekleri için using Microsoft.Data.SqlClient; gereklidir. SqlDbType, CommandType veya CommandBehavior kullanan örnekler de using System.Data; gerektirir.

Bağlantı kurulumu, kimlik doğrulama ve şifreleme için bkz. Bağlantı dizileri ve Şifreleme ve sertifika doğrulaması.

Bir çalıştırma yöntemi seçin

Beklenen sonucu eşleştiren yöntemi seçin:

Method Şu durumlarda kullanın: Sonuç
ExecuteNonQuery Komut veriyi veya şemayı değiştirir. Etkilenen satır sayısı. -1 sayım mevcut olmadığında da, SET NOCOUNT ON sayımları bastırdığında da meydana gelebilir.
ExecuteScalar Tek bir değere ihtiyacınız var. İlk satırın ilk sütunudur ya da sonuçta satır yoksa null. Bir veritabanı NULL olarak Value döndürülür.
ExecuteReader Satırlara, birden fazla sonuç setine veya şemaya ihtiyacınız var. Bir SqlDataReader.
ExecuteXmlReader Komut, XML'i ExecuteXmlReader tarafından gereken biçimde döndürür. Bir XmlReader.

Her yöntemin görev tabanlı asenkron bir karşılığı vardır. Çağıranın beklemeyi durdurması gerektiğinde bir CancellationToken geçirin. İptal ve zaman aşımı davranışı için bkz. Asenkron programlama.

Bir metin komutunu çalıştırın

CommandType.Text varsayılan değerdir. İfadeyi CommandText içine yerleştirin ve değerleri parametreler aracılığıyla iletin:

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

Parametre türleri, boyutlar, null değerler ve yönler için Parametreleri Yapılandır bölümüne bakınız. Güvenilmeyen değerleri CommandText içine birleştirmeyin.

Saklı bir yordam çalıştır

CommandType.StoredProcedure ayarlayın ve şema nitelikli yordam adını kullanın:

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, CommandType.StoredProcedure ve CommandType.Text destekler. CommandType.TableDirect ayarı, ArgumentOutOfRangeException oluşturur.

Her yöntemin ne verdiğini kontrol edin

Bir değere ihtiyacınız olduğunda kullanın ExecuteScalar :

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, sonuçta satır yoksa DBNull.Value ve ilk değer bir veritabanı null ise NULL döndürür.

Veri değiştiren ifadeler için ExecuteNonQuery kullanın. Bu örnek, AdventureWorks'un değişmemesi için değişikliği geri alıyor:

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 etkilenen satır sayılarını bastırır, böylece ExecuteNonQuery bir ifade veri değiştirdiğinde bile -1 geri döndürebilir.

Bir FOR XML sonuç için ExecuteXmlReader kullanın:

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

Yerel bir işlem kullanın

Bir bağlantının etkin bir yerel SqlTransaction varsa, bu işlemi bağlantıda yürütülen her komuta atayın. Bu örnek, yaptığı değişikliği geri alır; böylece AdventureWorks değişmeden kalır:

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

Yalnızca uygulama işlemin tamamını kabul ettiğinde Rollback yerine Commit çağırın. Aktif işleme başvurmayan bir komut InvalidOperationException fırlatır. İşlem başka bir bağlantıya aittiyse de yürütme başarısız olur. İşlem sınırları ve geri alma için Yerel işlemlere bakınız.

Bir komut zaman aşımı ayarlayın

CommandTimeout komut yürütme ve kümülatif ağ okuma beklemelerini saniyelerle sınırlar. Bir komut, bir tanesi yapılandırılmışsa bağlantının Command Timeout ayarını kullanır. Aksi takdirde, varsayılan süre 30 saniyedir. 0 değerinin zaman sınırı yoktur. Negatif değerler ArgumentException fırlatır.

Zaman aşımı dolduğunda, komut Number değeri -2 olarak ayarlanmış SqlException hatasını fırlatır:

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 bağlantı kurulumu ve havuz beklemelerini sınırlar. CommandTimeout komut yürütme başladıktan sonra başlar. Daha fazla bilgi için Bağlantı seçenekleri bölümüne bakınız.

Sınırlı bir zaman aşımını ve iptal tokenını birlikte kullanın. Zaman aşımı, veritabanı operasyonuna bir sınır koyar. Token'ın iptal edilmesi, zaman aşımı bitmeden kontrolü arayana geri verebilir. İptal ve zaman aşımının aynı istisna yarattığını varsaymayın.

Komutları yeniden kullanın ve hazırlayın

Bir parametreyi bir kez ekleyin ve her çalıştırma bittikten sonra değerini değiştirin:

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

Prepare öğesini yalnızca ölçümler bunu gerektirdiğinde çağırın. Prepare parametresiz saklı yordamları veya metin komutlarını hazırlamaz. Parametreleştirilmiş metin için, Prepare çağırmadan önce her parametreye Size, Precision ve Scale gibi tam meta veriler ayarlayın.

Sorun giderme komutları

Veritabanı işlemi etrafında SqlException öğesini yakalayın ve sunucu birden fazla hata döndürdüğünde Errors koleksiyonunu inceleyin. Komut hataları, uyarılar ve bilgilendirici mesajlar için bkz. Hataları ve mesajları ele almak.

Bir hata daha fazla bağlam gerektirdiğinde tanılama sayaçları, olay kaynağı izleme ve SqlClient sorun giderme rehberini kullanın. Yalnızca komut tekrarı güvenli olduğunda yapılandırılabilir yeniden deneme mantığını uygulayın.