BsonDocument and BsonValue - how can I add custom types with [BsonExtraElements]

4,301 views
Skip to first unread message

FiddlerMaddog

unread,
Jan 4, 2012, 10:39:57 AM1/4/12
to mongodb-csharp
Hi,

I'm trying to migrate an old project from the unofficial driver to the
official driver.
I've used the `ExtendedProperties` Document object to hold a lot of
things, I can't seem to find the correct way of doing it with the
official driver.

1) I'm trying to add some custom type values to the BsonDocument like
this:

doc.Add("key1", new Person());

and visual studio says that I can't do this, I tried using
BsonValue.Create and it fails with this message:
"System.ArgumentException: .NET type MyProject.Person cannot be mapped
to a BsonValue. I tried with enumerables and ToBsonDocument and got:
"System.InvalidOperationException: An Array value cannot be written to
the root level of a BSON document."

2) I'm trying to read things back from BsonDocument - my old code used
Document.Get<T> and casting was possible, should I use cast on
BsonValue.RawValue? This seems like the only possible way and it's
pretty cumbersome compared to the old way.

Thank you.

Robert Stam

unread,
Jan 4, 2012, 10:52:06 AM1/4/12
to mongodb...@googlegroups.com
[BsonExtraElements] is mostly intended to hold extra elements so that they successfully round trip from the database to your application and back. You can definitely do anything you want with them, but the values stored in them are of type BsonValue (some of which may be BsonDocuments), so you have to convert back and forth from instances of your class to BsonValue.

You can't do this with simple casting. you have to serialize/deserialize your classes to/from BsonValue.

To serialize an instance of Person as a BsonDocument and add it to your doc variable you can write this:
 
    var person = new Person();
    doc.Add("key1", person.ToBsonDocument());

To go in the other direction you can write this:

    person = BsonSerializer.Deserialize<Person>(doc["key1"].AsBsonDocument);

FiddlerMaddog

unread,
Jan 4, 2012, 11:13:17 AM1/4/12
to mongodb-csharp
What about arrays? Do I have to do this with each entry of the array
before insertion? And that's the only way?

That's insanely uncomfortable, I store Dictionary/Person/Enumerable/
Simple Type (like int/string/bool) - each one will need different
handling in order to put into the BsonDocument object.

I don't think I want to do all this work... what will be the
disadvantages of changing this from BsonDocument/BsonExtraElements to
a plain Dictionary<string, object>? What would stop working? Would
attributes still work on the dictionary values? Like if I put a Person
object in the dictionary and the Age member has [BsonDefaultValue],
would it still work?

Thank you


On Jan 4, 5:52 pm, Robert Stam <rob...@10gen.com> wrote:
> [BsonExtraElements] is mostly intended to hold extra elements so that
> they successfully round trip from the database to your application and
> back. You can definitely do anything you want with them, but the values
> stored in them are of type BsonValue (some of which may be BsonDocuments),
> so you have to convert back and forth from instances of your class to
> BsonValue.
>
> You can't do this with simple casting. you have to serialize/deserialize
> your classes to/from BsonValue.
>
> To serialize an instance of Person as a BsonDocument and add it to your doc
> variable you can write this:
>
>     var person = new Person();
>     doc.Add("key1", person.ToBsonDocument());
>
> To go in the other direction you can write this:
>
>     person = BsonSerializer.Deserialize<Person>(doc["key1"].AsBsonDocument);
>

Robert Stam

unread,
Jan 4, 2012, 11:30:11 AM1/4/12
to mongodb...@googlegroups.com
Using a Dictionary<string, object> would work (but it's not what [BsonExtraElements] uses).

Expect all the serialized objects in your Dictionary to have a "_t" discriminator value so that the Deserializer knows what type of object to instantiate.

FiddlerMaddog

unread,
Jan 5, 2012, 7:53:42 AM1/5/12
to mongodb-csharp
Using Dictionary<string, object> allows me to have code very similar
to what I had with the unofficial driver's `Document` object, which is
a lot easier to work with when working with arbitrary data (IMO).

But I hadn't thought of the fact that it would be under a new element
and not at the root of the record, so it can't be made backwards
compatible. Well, what can you do... I guess that's easier to fix.

Thank you, as always you are very helpful


On Jan 4, 6:30 pm, Robert Stam <rob...@10gen.com> wrote:
> Using a Dictionary<string, object> would work (but it's not what
> [BsonExtraElements] uses).
>
> Expect all the serialized objects in your Dictionary to have a "_t"
> discriminator value so that the Deserializer knows what type of object to
> instantiate.
>

aba...@stepoutsolutions.com

unread,
Nov 18, 2015, 2:32:34 AM11/18/15
to mongodb-csharp
hey your suggestion is actually perfect it works thank you so much..........
Reply all
Reply to author
Forward
0 new messages