BSON Serializer

eduardocampano edited this page Oct 29, 2010 · 28 revisions

NoRM’s BSON serializer is very powerful, and quite flexible. However, it is useful to understand the limits of BSON, and some general rules about what the NoRM serializer can handle. The serializer will make an effort to serialize any instance properties on your POCO, this includes private, protected, and internal properties. Fields & static members are ignored.

Requirements for Serialization of a Type:

  • All readable properties may be:
    • int
    • bool
    • double (floats will be stored as doubles in the db)
    • datetime
    • string
    • byte[]
    • ObjectId (this is the default “_id” value that’s generated if you don’t specify something different)
    • Regex
    • Guid
    • Enums backed by int or long (uint, ulong should work, too)
    • ScopedCode (a class that can define code for use inside of MongoDB)
    • IEnumerable<T> (where T follows these rules for serialization)
      • ICollection<T>, T[], List<T> are also supported (there are probably additional types that will serialize without any problems, but it’s recommended that you stick to this list).
    • IDictionary<TKey,TValue>
  • The type must declare an identifier property, “_id” or “ID” – if these are Guid/UUID, int?, or ObjectId, NoRM will take care of assigning a value on insert.
  • Cyclic graphs are not checked and attempting to serialize them will crash your app, maybe someday this will change, but not this day.
    • This is conceptually one of the main differences between a “Document DB” and an “Object DB” (Editor’s note: it’s taken years for db4o to achieve what it has with regard to cyclic graphs. If you’ve used it, you’ll understand that serializing a graph and then re-hydrating it is not a trivial problem, and maybe not one that Document DBs are well-suited to solve.)

Requirements for Deserialization of a Type:

  • The serialized properties must be writable (i.e. have a setter)
  • All of the types above are supported with these caveats:
    • Members of type T must follow these rules for Deserialization and T must be a class with a public default (parameterless) constructor.
    • Remember how floats are stored as doubles? They are deserialized to “double”

Other Notes:

  • decimal is not supported by the BSON specification, and therefore not supported by NoRM or MongoDB at this time.
  • Deserializing property names is done in a case-insensitive way, although MongoDB is case-sensitive. So it is recommended that you don’t store documents where property names vary only by case.
  • The serializer doesn’t hold your hand, if you ask it to deserialize a value and cast to a type that is illegal, you’ll pay the price for your sins.
    • A contributor has worked on a pluggable architecture for extending the serializer/deserializer with Type converters, this will be part of a future version of NoRM.
    • Know what you put into MongoDB and what you’re getting out.
  • A general rule in MongoDB is that no document be larger than 4MB, you must take care to adhere to this rule, NoRM will enforce this rule.
  • Due to MongoDB constraints, DateTime are stored with millisecond precision. If you need greater precision, use double.
    • DateTime is converted to UTC when it’s put into the DB, when it is returned from the DB, there is no reasonable guess about what timezone NoRM should translate it to. Therefore, NoRM will always deserialize the UTC equivalent of the DateTime you’ve stored.

Suggestions:

  • Use Nullable<T> instead of just “T” when possible, this will help to future-proof your POCOs.
  • Avoid Expando unless you need it, you get lots of benefits by having strongly-typed POCOs (think about LINQ queries).