title: protobuf-net and sql server ce
body: <p>We have been successfully using protobuf-net v1 in a compact framework application to handle serializing our objects for storage in a sql server ce database.</p>
  
  <p>Recently we hit a roadblock apparently due to using too many types (if we don't serialize as many types the error goes away.) Ref: <a href="http://code.google.com/p/protobuf-net/issues/detail?id=50#c6" rel="nofollow">http://code.google.com/p/protobuf-net/issues/detail?id=50#c6</a></p>
  
  <p>In desperation (we're supposed to be releasing soon) we downloaded v2 and have been using it (without pre-compiling the serializers). However, we are occassionally getting strange errors when deserializing data -- unknown wire-type 6 and an error reading an int-32 -- somehow it is getting an overflow error when casting to an int which doesn't make sense due to the fact that it was previously serialized using the same method...) It appears to me that we are getting some corruption of the binary data -- but we are simply storing in a varbinary field in sql server ce and pulling it back out. </p>
  
  <p>Does anyone have any ideas how the binary data could be corrupted? (See code below)</p>
  
  <p>FINAL FIX:</p>
  
  <p>Please read Marc's answer for some background. The best I can tell the problem was with how the SetBinary method works -- it does not appear to clear out or truncate existing data -- so if the binary data being saved is smaller than the previous data junk is left at the end.</p>
  
  <p>We fixed it by changing this:</p>
  
  <pre><code>if (buffer.Length &gt; 0)
  {
      record.SetBytes(insertSet.GetOrdinal(SerializedDataColumnName), 0, buffer, 0, buffer.Length);
  }
  </code></pre>
  
  <p>to this:</p>
  
  <pre><code>if (buffer.Length &gt; 0)
  {
      record.SetValue(insertSet.GetOrdinal(SerializedDataColumnName), null);
      record.SetBytes(insertSet.GetOrdinal(SerializedDataColumnName), 0, buffer, 0, buffer.Length);
  }
  </code></pre>
  
  <p>Thank you.</p>
  
  <p>UPDATE: 
  Code used to serialize to the DB (code suggestions welcome as well as problem areas):</p>
  
  <pre><code>command.CommandType = CommandType.TableDirect;
  MemoryStream ms = null;
  using (SqlCeResultSet insertSet = command.ExecuteResultSet(ResultSetOptions.Updatable))
  {
      foreach (var item in items)
      {
          ms = new MemoryStream();
          Serializer.Serialize&lt;T&gt;(ms, item);
          var record = insertSet.CreateRecord();
          var buffer = ms.GetBuffer();
          if (buffer.Length &gt; 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();
  }
  </code></pre>
  
  <p>Code used to deserialize:</p>
  
  <pre><code>using (var ms = new MemoryStream())
  {
      using (SqlCeResultSet recordSet = command.ExecuteResultSet(ResultSetOptions.Scrollable))
      {
          //var serializer = null; //ServiceDepository.TryGetProvider&lt;TypeModel, T&gt;();
          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 &gt; 0)
                  {
                      var ms2 = new MemoryStream(bytes);
                      item = Serializer.Deserialize&lt;T&gt;(ms2);
                  }
              }
              if (item == null)
              {
                  //handle 'empty' items -- there were no properties
                  //  that needed to be serialized
                  item = new T();
              }
              list.Add(item);
          }
      }
  }
  </code></pre>