Мы успешно используем protobuf-net v1 в компактном фреймворковом приложении для сериализации наших объектов для хранения в базе данных sql server ce.
Недавно мы столкнулись с препятствиями, по-видимому, из-за использования слишком большого количества типов (если мы не сериализовали столько типов, ошибка исчезнет). Ссылка: http://code.google.com/p/protobuf-net/issues/detail?id=50#c6
В отчаянии (мы должны скоро выпустить) мы загрузили v2 и использовали его (без предварительной компиляции сериализаторов). Тем не менее, мы иногда получаем странные ошибки при десериализации данных - неизвестный проводной тип 6 и ошибка чтения int-32 - каким-то образом он получает ошибку переполнения при преобразовании в int, что не имеет смысла из-за факта что он был предварительно сериализован с использованием того же метода ...) Мне кажется, что мы получаем некоторое повреждение двоичных данных - но мы просто храним в поле varbinary в sql server ce и извлекаем его обратно.
У кого-нибудь есть идеи, как двоичные данные могут быть повреждены? (См. Код ниже)
ФИНАЛЬНЫЙ ИСПРАВЛЕНИЕ:
Пожалуйста, прочитайте ответ Марка для некоторой предыстории. Самое лучшее, что я могу сказать, это то, как работает метод SetBinary - он, кажется, не очищает или не усекает существующие данные - поэтому, если сохраняемые двоичные данные меньше, чем предыдущий мусорный массив, оставленный в конце. 1012 *
Мы исправили это, изменив это:
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);
}
Спасибо.
UPDATE:
Код, используемый для сериализации в БД (приветствуются предложения кода и проблемные области):
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);
}
}
}