Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Используйте методы потоковой обработки Microsoft.Data.SqlClient для обработки больших значений без предварительной загрузки полного значения в память приложения. Потоковая передача полезна для бинарных файлов, крупного текста, XML, JSON и передачи между серверами.
Потоковая передача не делает значение поддерживающим произвольное позиционирование и не делает параллельные операции с читателем безопасными. Соединение, команда, считыватель, исходный поток и объект назначения должны оставаться активными до завершения передачи.
Примеры в этой статье предполагают, что открытое SqlConnection с именем connection нацелено на образцовую базу данных AdventureWorks.
Примеры C# требуют using Microsoft.Data.SqlClient;. Примеры, которые используют SqlDbType или CommandBehavior также требуют using System.Data;.
Передавать данные из базы данных SQL
Выполните команду с CommandBehavior.SequentialAccess и читайте столбцы по порядковым номерам. При последовательном доступе, после того как вы пройдёте мимо столбца, не читайте предыдущий столбец в той же строке.
Используйте следующие SqlDataReader методы:
| Метод | Результат | Типичные данные SQL |
|---|---|---|
| GetStream | Stream | бинарные, варбинарные, image и данные пользовательских типов (UDT) |
| GetTextReader | TextReader | Символьные данные и данные JSON |
| GetXmlReader | XmlReader | xml |
Вызовите IsDBNull перед запросом потока для столбца, допускающего значение NULL. Потоковый геттер, используемый с несовместимым SQL-типом, вызывает исключение. Считайте или освободите текущий поток перед чтением следующего столбца, продвижением строки или переходом к следующему результату.
GetStream не поддерживается для зашифрованных столбцов.
GetTextReader не поддерживает последовательный доступ к зашифрованному столбцу.
CommandTimeoutприменяется, пока Microsoft. Data.SqlClient ждёт сетевые пакеты во время выполнения и чтения. Время, которое ваше приложение тратит на обработку уже полученных данных, не учитывается. Для отмены и тайм-аутов см. Асинхронное программирование.
Передавать двоичные данные потоком
AdventureWorks хранит содержимое файла в столбце типа varbinary(max)Production.Document.Document, допускающем NULL. В этом примере одно значение копируется в файл с использованием ограниченного буфера:
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);
}
Для текста используйте GetTextReader и скопируйте в поле TextWriter. Для XML используйте GetXmlReader и обрабатывайте узлы XML без преобразования полного значения в строку.
Передавайте данные в базу данных SQL
Установите Value в потоковый объект и выберите совместимый тип SQL:
| Тип значения | Совместимые типы параметров |
|---|---|
| Stream |
Binary, VarBinary и устаревший тип Image |
| TextReader |
Char, NChar, VarChar, NVarChar, устаревшие типы Text и NText, Xml, и Json |
| XmlReader |
Char, NChar, VarChar, NVarChar, устаревшие типы Text и NText, Xml, и Json |
Задать Size явно.
Size ограничивает сумму переводимых средств. Используйте -1 для параметра (max), когда хотите отправить полный исходный текст.
Для передачи с ограниченной памятью используйте VarBinary, VarChar или NVarChar с Size = -1, или используйте Xml или Json. Microsoft.Data.SqlClient буферизирует исходные данные в байтовый массив или строку перед выполнением для несимвольных (max) и двоичных типов, а также для устаревших типов Image, Text и NText.
Потоковая передача значения параметра
В этом примере файл отправляется через параметр varbinary(max), и возвращается количество полученных байт. Он не сохраняет значение:
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");
Держите объект ввода открытым до завершения выполнения команды. Передайте токен отмены асинхронному методу выполнения или вызовите Cancel для запроса отмены операции потоковой передачи. Отмена выполняется по возможности. Операция может завершиться до выполнения отмены.
Исключение в исходном потоке или средстве чтения приводит к сбою выполнения команды. Не повторяйте попытку для того же объекта, если не сможете установить его положение и операция с базой данных не является безопасной для повторного выполнения.
Передавайте данные из одной SQL-базы данных в другую
В этом примере напрямую передаётся поток документов AdventureWorks в параметр в другом открытом SqlConnection с именем destinationConnection. Пример команды показывает полученную длину. Замените его на параметризованную команду вставки или обновления целевой базы данных:
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());
}
Команды source и destination не используют одну и ту же транзакцию. Если вашему приложению требуется согласованная атомарная работа между серверами, спроектируйте и протестируйте эту границу транзакции отдельно.