Я работал над способом предоставления доступа к крупным результатам SQL в виде потока, особенно когда запрос использует предложение for json или для xml.
Я заметил, что когда запрос возвращает json илиxml SqlDataReader
не позволяет использовать метод GetStream()
, который ожидается согласно документации:
'Недопустимая попытка GetStream для столбца' c '.Функция GetStream может использоваться только для столбцов типа Binary, Image, Udt или VarBinary. '
Однако, позволяет разрешать использование GetBytes()
.
Поведение является таким же, когда возвращаемые данные varchar(max)
или nvarchar(max)
.GetStream()
не будет работать, но GetBytes()
будет работать.
С обычным ограниченным по длине столбцом varchar
или nvarchar
ни GetStream
, ни GetBytes
не допускаются.
Возможность вызова GetBytes
означает, что я смог довольно легко создать пользовательский класс SqlTextStream : Stream
, при условии, что при чтении из nvarchar
, вероятно, лучше читать байты кратными двум, чтобы неРазбейте символы пополам.
Я просмотрел информацию, предоставленную SqlDataReader.GetColumnSchema()
, но не нашел очевидной причины, по которой GetBytes
допускается для n/varchar(max)
результатов.Возможно, я что-то пропустил, но вывод GetColumnSchema
кажется одинаковым для обычных или (макс.) Символьных данных, за исключением длины.
Кто-нибудь знает, почему GetBytes
разрешено для n/varchar(max)
столбцов?Как вы думаете, безопасно ли полагаться на то, что GetBytes
разрешено?
Вот несколько простых тестовых кодов:
public void Test()
{
var cmd1 = "select c = 'getbytes permitted here' for json path";
var cmd2 = "select c = cast('getbytes also permitted here' as nvarchar(max))";
var cmd3 = "select c = cast('getbytes not permitted here' as nvarchar(32))";
using (var con = new SqlConnection("data source=theDB; initial catalog=playground; integrated security=SSPI"))
// switch between cmd1, cmd2 and cmd3 to see the different behaviour.
using (var cmd = new SqlCommand(cmd1, con))
{
con.Open();
using (var rdr = cmd.ExecuteReader(System.Data.CommandBehavior.SequentialAccess))
{
var o = rdr.GetColumnSchema();
var buffer = new byte[128];
rdr.Read();
//System.IO.Stream s = rdr.GetStream(0); this is never permitted
rdr.GetBytes(0, 0, buffer, 0, buffer.Length); // this is permitted for cmd1 and cmd2
}
}
}