Какой параметр длины нужно передать в SqlDataReader.GetBytes()

У меня есть SqlDataReader и вам нужно прочитать столбец varbinary (max), используя метод SqlDataReader.GetBytes(). Этот метод заполняет массив байтов и поэтому должен знать, какую длину данных читать.

Вот где я запутался. Ясно, что я хочу прочитать все данные, которые были возвращены из базы данных в этой строке/столбце, и какой параметр "длины" должен пройти?

Насколько я вижу, SqlDataReader не предоставляет каких-либо методов для определения того, какая длина данных доступна, поэтому этот метод кажется мне довольно неудобным.

У меня возникает соблазн просто передать int.MaxValue здесь и забыть о проблеме, но что-то об этом не подходит мне.

Я знаю, что вместо этого я могу позвонить

byte[] value = (byte[])dataReader["columnName"];

.. и это, кажется, полностью заботится о проблеме длины внутри. Однако я работаю с набором сложных шаблонов генерации кода, которые были построены вокруг методов SqlDataReader.GetXXXX(). Поэтому я привязан к использованию GetBytes и должен понимать его правильное использование.

Ответы

Ответ 1

При работе с varbinary(max) существует два сценария:

  • длина данных умеренная
  • длина данных большая

GetBytes() предназначен для сценария второй, когда вы используете CommandBehaviour.SequentialAccess для обеспечения потоковой передачи данных, а не для буферизации. В частности, в этом использовании вы обычно пишете (например) в потоке в цикле. Например:

// moderately sized buffer; 8040 is a SQL Server page, note
byte[] buffer = new byte[8040]; 
long offset = 0;
int read;
while((read = reader.GetBytes(col, offset, buffer, 0, buffer.Length)) > 0) {
    offset += read;
    destination.Write(buffer, 0, read); // push downstream
}

Однако! Если вы используете данные умеренного размера, то ваш исходный код:

byte[] data = (byte[])reader[col];

отлично!. Нет ничего плохого в этом подходе, и на самом деле API-интерфейс Get* в некоторых случаях разбит на несколько случаев - GetChar() - заметный пример (подсказка: он не работает).

Не имеет значения, что у вас есть существующий код, который использует Get* - в этом случае подход отливки идеально подходит.

Ответ 2

Вы могли бы это сделать. Найдено на MSDN. Вероятно, это может служить вашей целью

    // Reset the starting byte for the new BLOB.
  startIndex = 0;

  // Read the bytes into outbyte[] and retain the number of bytes returned.
  retval = myReader.GetBytes(1, startIndex, outbyte, 0, bufferSize);

 // Continue reading and writing while there are bytes beyond the size of the buffer.
  while (retval == bufferSize)
  {
    bw.Write(outbyte);
    bw.Flush();

    // Reposition the start index to the end of the last buffer and fill the buffer.
    startIndex += bufferSize;
    retval = myReader.GetBytes(1, startIndex, outbyte, 0, bufferSize);
  }

  // Write the remaining buffer.
  bw.Write(outbyte, 0, (int)retval - 1);
  bw.Flush();

http://msdn.microsoft.com/en-us/library/87z0hy49%28v=vs.71%29.aspx#Y132

Или этот

int ndx = rdr.GetOrdinal("<ColumnName>");
            if(!rdr.IsDBNull(ndx))
           {
            long size = rdr.GetBytes(ndx, 0, null, 0, 0);  //get the length of data
            byte[] values = new byte[size];

            int bufferSize = 1024;
            long bytesRead = 0;
            int curPos = 0;

            while (bytesRead < size)
            {
                bytesRead += rdr.GetBytes(ndx, curPos, values, curPos, bufferSize);
                curPos += bufferSize;
            }
           }