Hacky Sql Компактный обходной путь - PullRequest
2 голосов
/ 30 декабря 2008

Итак, я пытаюсь использовать ADO.NET для потоковой передачи данных файла, хранящихся в столбце изображения в базе данных SQL Compact.

Для этого я написал класс DataReaderStream, который принимает считыватель данных, открывается для последовательного доступа и представляет его как поток, перенаправляя вызовы Read (...) в потоке в IDataReader.GetBytes (... ).

Один «странный» аспект IDataReader.GetBytes (...) по сравнению с классом Stream заключается в том, что GetBytes требует, чтобы клиент увеличивал смещение и передавал его при каждом вызове. Он делает это, даже если доступ является последовательным, и невозможно прочитать «назад» в потоке устройства чтения данных.

Реализация IDataReader в SqlCeDataReader усиливает это, увеличивая внутренний счетчик, который определяет общее количество возвращенных байтов. Если вы передадите число, которое меньше или больше этого числа, метод сгенерирует исключение 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, не прибегая к такому ужасному коду?

Ответы [ 2 ]

1 голос
/ 31 декабря 2008

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

0 голосов
/ 31 декабря 2008

На самом деле, я решил исправить эту проблему, просто не сохраняя BLOB-объекты в базе данных для начала.

Это устраняет проблему (я могу передавать данные из файла), а также устраняет некоторые проблемы, с которыми я мог столкнуться при ограничении размера Sql Compact в 4 ГБ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...