SqlClient akış desteği

Microsoft.Data.SqlClient akış yöntemlerini kullanarak büyük değerleri, değerin tamamını önce uygulama belleğine yüklemeden işlemek. Akış, ikili dosyalar, büyük metinler, XML, JSON ve sunucudan sunucuya aktarım için faydalıdır.

Akış, değeri konumlandırılabilir kılmaz veya okuyucuda eşzamanlı işlemleri güvenli hale getirmez. Bağlantı, komut, okuyucu, kaynak akışı ve hedef nesne, aktarım tamamlanana kadar varlığını korumalıdır.

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

C# örnekleri için using Microsoft.Data.SqlClient; gereklidir. SqlDbType veya CommandBehavior kullanan örnekler için using System.Data; da gerekir.

SQL veritabanından veri akışı sağlayın

Komutu CommandBehavior.SequentialAccess ile çalıştırın ve sütunları sıra numarasına göre okuyun. Sıralı erişimde, bir sütunu geçtikten sonra aynı satırdaki önceki bir sütunu okumayın.

Bu SqlDataReader yöntemleri kullanın:

Method Sonuç Tipik SQL verisi
GetStream Stream binary, varbinary, image ve kullanıcı tanımlı tür (UDT) verileri
GetTextReader TextReader Karakter ve JSON verileri
GetXmlReader XmlReader xml

Nullable bir sütun için akış talep etmeden önce IsDBNull çağırın. Uyumsuz bir SQL tipiyle kullanılan bir akış getteri özel durum fırlatır. Başka bir sütunu okumadan, satırı ilerletmeden veya bir sonraki sonuca geçmeden önce mevcut akışı tüketin veya atın.

Şifreli sütunlar için GetStream desteklenmez. GetTextReader şifreli bir sütuna ardışık erişimi desteklemez.

CommandTimeout, Microsoft.Data.SqlClient yürütme ve okuma sırasında ağ paketlerini beklerken uygulanır. Başvurunuzun zaten alınan verileri işlemek için harcadığı zaman hesaba katılmaz. İptal ve zaman aşımları için bkz. Asenkron programlama.

İkili veri akışı

AdventureWorks, dosya içeriğini null değer alabilen varbinary(max)Production.Document.Document sütununda saklar. Bu örnek, sınırlı bir arabellek kullanarak bir değeri bir dosyaya kopyalar:

using var command = new SqlCommand("""
    SELECT TOP (1) Document
    FROM Production.Document
    WHERE Document IS NOT NULL
    ORDER BY ModifiedDate DESC;
    """, connection);

using SqlDataReader reader = command.ExecuteReader(
    CommandBehavior.SequentialAccess);
if (reader.Read())
{
    using Stream source = reader.GetStream(0);
    using FileStream destination = File.Create("document.bin");
    source.CopyTo(destination);
}

Metin için GetTextReader kullanın ve bir TextWriter içine kopyalayın. XML için, GetXmlReader kullanın ve tam değeri dizeye dönüştürmeden XML düğümlerini işleyin.

Verileri bir SQL veritabanına aktarın

Bir akış nesnesine ayarlayın Value ve uyumlu bir SQL türü seçin:

Değer türü Uyumlu parametre türleri
Stream Binary, VarBinary, ve miras Image tipi
TextReader Char, NChar, VarChar, NVarChar, eski Text ve NText tipleri, Xml ve Json
XmlReader Char, NChar, VarChar, NVarChar, eski Text ve NText türleri, Xml, ve Json

Açık şekilde ayarlayın Size . Size Transfer edilen miktarı sınırlar. Tam kaynağı göndermek istediğinizde -1 parametresi için (max) kullanın.

Sınırlı bellek transferi için, VarBinary, VarCharveya NVarChar ile Size = -1, veya Xml veya Json. Microsoft.Data.SqlClient, yürütmeden önce (max) dışındaki karakter ve ikili türler ile eski Image, Text ve NText türleri için kaynağı bir bayt dizisine veya dizeye arabelleğe alır.

Bir parametre değerini akışa aktar

Bu örnek, bir dosyayı varbinary(max) parametresi üzerinden gönderir ve alınan bayt sayısını döndürür. Değeri depolamıyor:

using FileStream input = File.OpenRead("document.bin");
using var command = new SqlCommand(
    "SELECT DATALENGTH(@content);",
    connection);
command.Parameters.Add(
    new SqlParameter("@content", SqlDbType.VarBinary, -1)
    {
        Value = input
    });

long length = (long)command.ExecuteScalar()!;
Console.WriteLine($"{length} bytes");

Komut çalıştırması tamamlanana kadar giriş nesnesini açık tutun. İptal belirtecini asenkron bir yürütme yöntemine iletin veya akış işleminin iptalini istemek için Cancel çağrısı yapın. İptal işlemi, mümkün olduğunca gerçekleştirilir. Operasyon, iptal yürürlüğe girmeden önce tamamlanabilir.

Kaynak akışından veya okuyucudan kaynaklanan bir istisna, komut yürütmesini hataya uğratır. Yalnızca aynı nesnenin konumunu belirleyebiliyorsanız ve veritabanı işlemini güvenle tekrarlayabiliyorsanız yeniden deneyin.

Bir SQL veritabanından diğerine veri aktarın

Bu örnek, AdventureWorks belge akışını doğrudan destinationConnection adlı başka bir açık SqlConnection üzerindeki bir parametreye iletir. Örnek komutu alınan uzunluğu bildirir. Bunu hedef veritabanının parametreli insert or update komutuyla değiştirin:

using var readSource = new SqlCommand("""
    SELECT TOP (1) Document
    FROM Production.Document
    WHERE Document IS NOT NULL
    ORDER BY ModifiedDate DESC;
    """, connection);

using SqlDataReader sourceReader = readSource.ExecuteReader(
    CommandBehavior.SequentialAccess);

if (sourceReader.Read())
{
    using Stream content = sourceReader.GetStream(0);
    using var write = new SqlCommand(
        "SELECT DATALENGTH(@content);",
        destinationConnection);
    write.Parameters.Add(
        new SqlParameter("@content", SqlDbType.VarBinary, -1)
        {
            Value = content
        });

    Console.WriteLine(write.ExecuteScalar());
}

Kaynak ve hedef komutlar bir işlemi paylaşmaz. Uygulamanız sunucular arasında koordineli atomik çalışma gerektiriyorsa, o işlem sınırını ayrı tasarlayın ve test edin.