Streamingondersteuning voor SqlClient

Gebruik Microsoft. Data.SqlClient-streamingmethoden om grote waarden te verwerken zonder eerst de volledige waarde in het applicatiegeheugen te laden. Streaming is nuttig voor binaire bestanden, grote tekst, XML, JSON en server-naar-server overdracht.

Streaming maakt de waarde niet geschikt voor willekeurige toegang en maakt gelijktijdige bewerkingen op een lezer niet veilig. De verbinding, het commando, de lezer, de bronstroom en het bestemmingsobject moeten actief blijven tot de overdracht is voltooid.

De voorbeelden in dit artikel gaan ervan uit dat een open SqlConnection met de naam connection gericht is op de AdventureWorks-voorbeelddatabase.

De C#-voorbeelden vereisen using Microsoft.Data.SqlClient;. Voorbeelden die gebruik maken van SqlDbType of CommandBehavior, vereisen ook using System.Data;.

Stream data uit een SQL-database

Voer het commando uit met CommandBehavior.SequentialAccess en lees kolommen in volgorde van index. Met sequentiële toegang lees je, nadat je voorbij een kolom bent gegaan, geen eerdere kolom in dezelfde rij.

Gebruik deze SqlDataReader methoden:

Method Result Typische SQL-gegevens
GetStream Stream binary, varbinary, image en gegevens van door de gebruiker gedefinieerde typen (UDT)
GetTextReader TextReader Karakter- en JSON-gegevens
GetXmlReader XmlReader xml

Bel IsDBNull voordat je een stream aanvraagt voor een nullable column. Een streaminggetter gebruikt met een incompatibel SQL-type veroorzaakt een exceptie. Gebruik of gooi de huidige stream weg voordat je een andere kolom leest, de rij verplaatst of naar de volgende resultset gaat.

GetStream wordt niet ondersteund voor versleutelde kolommen. GetTextReader ondersteunt geen sequentiële toegang tot een versleutelde kolom.

CommandTimeout Dit geldt terwijl Microsoft.Data.SqlClient wacht op netwerkpakketten tijdens uitvoering en lezen. De tijd die je applicatie besteedt aan het verwerken van reeds ontvangen gegevens wordt niet meegeteld. Voor annulering en timeouts, zie Asynchrone programmering.

Binaire gegevens streamen

AdventureWorks slaat bestandsinhoud op in de nullable varbinary(max)Production.Document.Document -kolom. Dit voorbeeld kopieert één waarde naar een bestand met een begrensde buffer:

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

Voor tekst gebruik GetTextReader en kopieer naar een TextWriter. Voor XML gebruik GetXmlReader en verwerk XML-nodes zonder de volledige waarde om te zetten in string.

Stream data naar een SQL-database

Stel Value in op een streaming-object en kies een compatibel SQL-type:

Waardetype Compatibele parametertypes
Stream Binary, VarBinary, en het legacy-type Image
TextReader Char, Text, NText, Xml, de legacy NVarChar- en VarChar-typen, NChar, en Json
XmlReader Char, Text, NText, Xml, de legacy NVarChar- en VarChar-typen, NChar, en Json

Stel Size expliciet in. Size beperkt het over te maken bedrag. Gebruik -1 voor een (max) parameter als je de volledige bron wilt versturen.

Voor begrensde geheugenoverdracht gebruik VarBinary, VarChar of NVarChar met Size = -1, of gebruik Xml of Json. Microsoft.Data.SqlClient buffert de bron in een bytearray of tekenreeks vóór uitvoering voor niet-(max)-teken- en binaire typen en de legacytypen Image, Text en NText.

Stream een parameterwaarde

Dit voorbeeld stuurt een bestand via een varbinary(max) -parameter en geeft het aantal ontvangen bytes terug. Het slaat de waarde niet op:

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

Houd het invoerobject open totdat de uitvoering van het commando is voltooid. Geef een annuleringstoken door aan een asynchrone uitvoeringsmethode of roep Cancel aan om annulering van de streamingoperatie aan te vragen. Annuleren gebeurt op basis van best effort. De bewerking kan worden afgerond voordat de annulering van kracht wordt.

Een uitzondering uit de bronstroom of een fout in de lezer verstoort de uitvoering van de opdracht. Probeer het niet opnieuw vanaf hetzelfde object tenzij je de positie kunt vaststellen en de databasebewerking veilig is om te herhalen.

Stream data van de ene SQL-database naar de andere

Dit voorbeeld stuurt een AdventureWorks-documentstroom direct naar een parameter op een andere geopende SqlConnection met de naam destinationConnection. Het voorbeeldcommando geeft de ontvangen lengte weer. Vervang het door het geparametriseerde insert- of updatecommando van de bestemmingsdatabase:

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

De bron- en bestemmingscommando's delen geen transactie. Als je applicatie gecoördineerd atomair werk over servers vereist, ontwerp en test dan die transactiegrens apart.