【问题标题】:protobuf-net and sql server ceprotobuf-net 和 sql server ce
【发布时间】:2011-02-10 01:34:45
【问题描述】:

我们已经成功地在一个紧凑的框架应用程序中使用 protobuf-net v1 来处理序列化我们的对象以存储在 sql server ce 数据库中。

最近我们显然遇到了障碍,因为使用了太多类型(如果我们不序列化尽可能多的类型,错误就会消失。)参考:http://code.google.com/p/protobuf-net/issues/detail?id=50#c6

在绝望中(我们应该很快发布)我们下载了 v2 并一直在使用它(没有预编译序列化程序)。但是,我们在反序列化数据时偶尔会遇到奇怪的错误——未知的线类型 6 和读取 int-32 的错误——不知何故,在转换为 int 时会出现溢出错误,由于事实原因,这是没有意义的它以前是使用相同的方法序列化的...)在我看来,我们正在损坏二进制数据——但我们只是将其存储在 sql server ce 的 varbinary 字段中并将其拉回。

有没有人知道二进制数据是如何被破坏的? (见下面的代码)

最终修复:

请阅读 Marc 的回答以了解一些背景。我能说的最好的问题是 SetBinary 方法是如何工作的——它似乎不会清除或截断现有数据——所以如果要保存的二进制数据小于之前的数据,那么最后就会留下垃圾。

我们通过改变这个来修复它:

if (buffer.Length > 0)
{
    record.SetBytes(insertSet.GetOrdinal(SerializedDataColumnName), 0, buffer, 0, buffer.Length);
}

到这里:

if (buffer.Length > 0)
{
    record.SetValue(insertSet.GetOrdinal(SerializedDataColumnName), null);
    record.SetBytes(insertSet.GetOrdinal(SerializedDataColumnName), 0, buffer, 0, buffer.Length);
}

谢谢。

更新: 用于序列化到数据库的代码(欢迎提供代码建议以及问题区域):

command.CommandType = CommandType.TableDirect;
MemoryStream ms = null;
using (SqlCeResultSet insertSet = command.ExecuteResultSet(ResultSetOptions.Updatable))
{
    foreach (var item in items)
    {
        ms = new MemoryStream();
        Serializer.Serialize<T>(ms, item);
        var record = insertSet.CreateRecord();
        var buffer = ms.GetBuffer();
        if (buffer.Length > 0)
        {
            record.SetBytes(insertSet.GetOrdinal(SerializedDataColumnName), 0, buffer, 0, buffer.Length);
        }
        else
        {
            record.SetValue(insertSet.GetOrdinal(SerializedDataColumnName), null);
        }
        insertSet.Update();
    }
}
if (ms != null)
{
    ms.Dispose();
}

用于反序列化的代码:

using (var ms = new MemoryStream())
{
    using (SqlCeResultSet recordSet = command.ExecuteResultSet(ResultSetOptions.Scrollable))
    {
        //var serializer = null; //ServiceDepository.TryGetProvider<TypeModel, T>();
        while (recordSet.Read())
        {
            if (!recordSet.IsDBNull(recordSet.GetOrdinal(SerializedDataColumnName)))
            {
                var count = recordSet.GetBytes(recordSet.GetOrdinal(SerializedDataColumnName), 0, null, 0, 1);
                var bytes = new byte[count];
                recordSet.GetBytes(recordSet.GetOrdinal(SerializedDataColumnName), 0, bytes, 0, (int)count);
                if (bytes.Length > 0)
                {
                    var ms2 = new MemoryStream(bytes);
                    item = Serializer.Deserialize<T>(ms2);
                }
            }
            if (item == null)
            {
                //handle 'empty' items -- there were no properties
                //  that needed to be serialized
                item = new T();
            }
            list.Add(item);
        }
    }
}

【问题讨论】:

  • 如果你有可重现的例子,我很乐意调查(我是作者)。
  • @Marc:这是问题的很大一部分(以及为什么我在这里发帖而不是在 protobuf-net 网站上注册错误)。它是随机的,我无法确定重现场景,我不确定是 protobuf-net 错误还是我使用 sql server ce 二进制存储的问题。
  • @Steve 你能分享任何序列化代码,以便我进行完整性检查吗?
  • @Marc:添加了代码示例。我也一直在尝试使用 v2 中的预编译选项但没有成功,但这是一个更容易调试的问题,所以我试图缩小范围。如果我给你一些不会反序列化(使用对象)的二进制数据样本,是否可以说明问题所在?
  • @Steve - 不,我想我看到了...... 2 秒

标签: sql-server-ce protobuf-net


【解决方案1】:

我可以看到一个问题;您正在向 MemoryStream 询问 GetBuffer 并使用缓冲区的长度。这里一个可能的问题是 GetBuffer 返回 oversized 后备缓冲区;您应该在 MemoryStream 上调用 .ToArray() 以获得正确大小的缓冲区,或者如果您不想分配额外的数组,您可以调用 GetBuffer() 但您必须只存储第一个memStream.Length 来自该缓冲区的字节;其余的应视为垃圾(很可能全为零,但前导零在 protobuf 字段标头中无效)。

现在,这可能只是问题的一部分,但我们应该首先消除它...

【讨论】:

  • 太棒了,我会试试的,非常感谢。在 v2 中,如果我可以使用预编译的序列化程序,事情会更快,对吗?
  • @Steve 是的,但是为 CF 打包的 robust 代码仍在进行中;目前它只会使用运行时(非常像 v1 那样),但希望你会发现你没有得到烦人的 MissingMethodException 等。当它 完全编译时(作为构建的一部分,当该代码已完全完善)它应该会明显更快。
  • @Steve 总结一下:目前它的速度应该与 v1 类似,但没有终端故障;当包装器准备好时,速度会提高。我怀疑我可能需要为此切换到 IKVM,但不是什么大问题。
  • 查看 Marc 的回答... @Marc:我很抱歉 - 我一直在忙于寻找内存不足的错误,并且没有解决这个特定的问题。与此同时,显然我清除了我的 cookie,因为 Stack Overflow 不再识别我,而且我还没有弄清楚如何让它知道我是 那个 未注册用户......我不是注册用户希望我不再给任何人带来不便。在我获得足够的“积分”发表评论之前,我无法回复。我仍然遇到问题,但还没有想出一些我可以发送但没有大量客户的可重现二进制数据
  • 1.感谢 Marc 解决了我的 SO 用户问题。 2. 看起来 Marc 估计问题是缓冲区末尾的垃圾数据是正确的。请参阅原始问题中的 FIX。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多