Итак, я пытаюсь использовать ADO.NET для потоковой передачи файловых данных, хранящихся в столбце изображения в базе данных SQL Compact.
Для этого я написал класс DataReaderStream, который принимает средство чтения данных, открытый для последовательного доступа, и представляет его как поток, перенаправляя вызовы Read (...) в потоке на IDataReader.GetBytes (...).
Один «странный» аспект IDataReader.GetBytes (...) по сравнению с классом Stream заключается в том, что GetBytes требует, чтобы клиент увеличивал смещение и передавал его при каждом вызове. Он делает это, даже если доступ является последовательным, и невозможно читать "назад" в потоке чтения данных.
Реализация SqlCeDataReader IDataReader обеспечивает это, увеличивая внутренний счетчик, который определяет общее количество возвращенных байтов. Если вы передадите число, меньшее или большее, чем это число, метод выдаст исключение InvalidOperationException.
Однако проблема заключается в том, что в реализации SqlCeDataReader есть ошибка, из-за которой внутренний счетчик устанавливает неправильное значение. Это приводит к тому, что последующие вызовы Read в моем потоке выдают исключения, когда их не должно быть.
Я нашел информацию об ошибке на этот поток MSDN.
Мне удалось придумать отвратительный, ужасно хитрый обходной путь, который в основном использует отражение для обновления поля в классе до правильного значения.
Код выглядит так:
public override int Read(byte[] buffer, int offset, int count)
{
m_length = m_length ?? m_dr.GetBytes(0, 0, null, offset, count);
if (m_fieldOffSet < m_length)
{
var bytesRead = m_dr.GetBytes(0, m_fieldOffSet, buffer, offset, count);
m_fieldOffSet += bytesRead;
if (m_dr is SqlCeDataReader)
{
//BEGIN HACK
//This is a horrible HACK.
m_field = m_field ?? typeof (SqlCeDataReader).GetField("sequentialUnitsRead", BindingFlags.NonPublic | BindingFlags.Instance);
var length = (long)(m_field.GetValue(m_dr));
if (length != m_fieldOffSet)
{
m_field.SetValue(m_dr, m_fieldOffSet);
}
//END HACK
}
return (int) bytesRead;
}
else
{
return 0;
}
}
По понятным причинам я бы предпочел не использовать это.
Однако я также не хочу буферизовать все содержимое большого двоичного объекта в памяти.
Кто-нибудь знает, как я могу получить потоковые данные из базы данных SQL Compact, не прибегая к такому ужасному коду?


Я связался с Microsoft (через блог SQL Compact), они подтвердили ошибку и предложили мне использовать OLEDB в качестве временного решения. Итак, я попробую это и посмотрю, сработает ли это для меня.
Собственно, я решил решить проблему, просто не сохраняя капли в базе данных с самого начала.
Это устраняет проблему (я могу передавать данные из файла), а также исправляет некоторые проблемы, с которыми я мог столкнуться с ограничением размера Sql Compact 4 ГБ.