【发布时间】: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