Hacky Sql Compact解决方法

时间:2008-12-30 07:27:58

标签: sql sql-server database

所以,我正在尝试使用ADO.NET来传输存储在SQL Compact数据库中的image列中的文件数据。

为此,我编写了一个DataReaderStream类,它接受一个数据读取器,为顺序访问打开,并将其表示为流,将流上的Read(...)重定向到IDataReader.GetBytes(... )。

与Stream类相比,IDataReader.GetBytes(...)的一个“怪异”方面是GetBytes要求客户端增加偏移量并在每次调用时传递它。即使访问是连续的,它也会这样做,并且不可能在数据读取器流中“向后”读取。

IDataReader的SqlCeDataReader实现通过递增一个内部计数器来强制执行此操作,该计数器标识它返回的总字节数。如果传入的数字小于或大于该数字,则该方法将抛出InvalidOperationException。

然而,问题在于SqlCeDataReader实现中存在一个错误,导致它将内部计数器设置为错误的值。这导致后续调用我的流上的Read会抛出不应该出现的异常。

我在this MSDN thread上找到了有关该错误的一些信息。

我能够想出一个令人作呕的,可怕的hacky解决方法,它基本上使用反射将类中的字段更新为正确的值。

代码如下所示:

    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;
        }
    }

出于显而易见的原因,我宁愿不使用它。

但是,我不想在内存中缓冲blob的全部内容。

有没有人知道我可以从SQL Compact数据库中获取流数据而不必诉诸这些可怕的代码?

2 个答案:

答案 0 :(得分:1)

我联系了Microsoft(通过SQL Compact博客),他们确认了这个错误,并建议我使用OLEDB作为解决方法。所以,我会尝试一下,看看这对我有用。

答案 1 :(得分:-1)

实际上,我决定通过不在数据库中存储blob来解决问题。

这消除了问题(我可以从文件中传输数据),还修复了我可能遇到的一些问题,包括Sql Compact的4 GB大小限制。