Az SqlClient streamelésének támogatása

Használj Microsoft. Data.SqlClient streaming módszereket nagy értékek feldolgozására anélkül, hogy előbb a teljes értéket betöltenénk az alkalmazásmemóriába. A streamelés hasznos bináris fájlokhoz, nagy szöveghez, XML-hez, JSON-hoz és szerverek közötti átvitelhez.

A streaming nem teszi az értéket pozicionálhatóvá, és nem teszi biztonságossá az egyidejű műveleteket az olvasón. A kapcsolatnak, parancsnak, olvasónak, forrásfolyamnak és célobjektumnak életben kell maradnia az átvitel befejezéséig.

A cikkben szereplő példák feltételezik, hogy egy megnyitott SqlConnection nevű connection az AdventureWorks mintaadatbázisra mutat.

A C#-példák megkövetelik a(z) using Microsoft.Data.SqlClient; használatát. Azok a példák, amelyek SqlDbType-t vagy CommandBehavior-et használnak, szintén megkövetelik a(z) using System.Data;-t.

Adatok streamelése SQL-adatbázisból

A parancsot CommandBehavior.SequentialAccess hajtsd végre, és olvasd el az oszlopokat sorrendben. Szekvenciális hozzáférés esetén, miután túlléptél egy oszlopon, ne olvass egy korábbi oszlopot ugyanabban a sorban.

Használd ezeket SqlDataReader a módszereket:

Method Result Minta SQL-adatok
GetStream Stream binary, varbinary, image és felhasználó által definiált típusú (UDT) adatok
GetTextReader TextReader Karakter- és JSON adatok
GetXmlReader XmlReader xml

Hívd meg a(z) IsDBNull elemet, mielőtt streamet kérnél egy nullable oszlophoz. Egy streaming getter, amit nem kompatibilis SQL típussal használnak, kivételt dob. Fogyasztsd vagy dobd el az aktuális adatfolyamot, mielőtt egy másik oszlopot olvasnál, előrelépnél a sorban, vagy a következő eredményre lépnél.

A titkosított oszlopok nem támogatottak a(z) GetStream esetében. GetTextReader nem támogatja a titkosított oszlophoz való szekvenciális hozzáférést.

CommandTimeout akkor érvényes, amikor a Microsoft.Data.SqlClient hálózati csomagokra vár a végrehajtás és az olvasás során. Az idő, amit az alkalmazásod a már beérkezett adatok feldolgozására fordít, nem számít. A törlés és időkorlátok esetén lásd: Aszinkron programozás.

Bináris adatok streamelése

Az AdventureWorks a fájltartalmat a nullable varbinary(max)Production.Document.Document oszlopban tárolja. Ez a példa egy értéket másol egy fájlba, korlátos puffert használva:

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

Szöveghez használd GetTextReader és másold át ide: TextWriter XML-hez használd GetXmlReader és dolgozd fel az XML csomópontokat anélkül, hogy a teljes értéket sztringgé konvertálnád.

Adatok továbbítása SQL-adatbázisba

Állítsd a(z) Value értékét streaming objektumra, és válassz kompatibilis SQL-típust:

Érték típusa Kompatibilis paramétertípusok
Stream Binary, VarBinary, és a legacy Image típus
TextReader Char, NChar, VarChar, NVarChar, az örökölt Text és NText típusok, Xml, és Json
XmlReader Char, NChar, VarChar, NVarChar, az örökölt Text és NText típusok, Xml, és Json

Állítsa be Size explicit módon. Size korlátozza az átvitt összeget. Használja a(z) -1 elemet (max) paraméterként, amikor a teljes forrást szeretné elküldeni.

Korlátos memóriaátvitelhez használjunk VarBinary, VarChar, vagy NVarChar a(z) Size = -1 használatával, vagy Xml, vagy Json. A Microsoft.Data.SqlClient a forrást egy bájttömbbe vagy sztringbe puffereli a végrehajtás előtt a nem (max) karakteres és bináris típusok, valamint a régi Image, Text és NText típusok esetén.

Paraméterérték streamelése

Ez a példa egy fájlt egy varbinary(max) paraméteren keresztül küld, és visszaadja a kapott bájtok számát. Nem tárolja az értéket:

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

Tartsd nyitva a bemeneti objektumot, amíg a parancs végrehajtása be nem fejeződik. Adj át egy megszakítási tokent egy aszinkron végrehajtási metódusnak, vagy hívd meg a(z) Cancel elemet a streamelési művelet megszakításának kérésére. A lemondás 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.

A forrásfolyam vagy az olvasó kivétele meghiúsítja a parancs végrehajtását. Ne próbáld újra ugyanazzal az objektummal, hacsak nem tudod megállapítani a pozícióját, és az adatbázis-művelet biztonságosan megismételhető.

Adatok továbbítása egyik SQL adatbázisból a másikba

Ez a példa egy AdventureWorks dokumentumfolyamot közvetlenül egy másik, destinationConnection nevű nyitott SqlConnection paraméteréhez továbbít. A mintaparancs a fogadott hosszát jelzi. Cseréld le a céladatbázis paraméterezett beszúrási vagy frissítési parancsára:

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

A forrás- és célparancsok nem ugyanazt a tranzakciót használják. Ha az alkalmazásod koordinált atomi munkát igényel szerverek között, tervezd meg és teszteld ezt a tranzakciós határt külön.