MongoDB C# BsonRepresentation of an Array of ObjectIds

7,826 views
Skip to first unread message

Максим Пономарев

unread,
May 28, 2012, 7:46:23 AM5/28/12
to mongodb...@googlegroups.com
I have such scheme of document:
{
 
"_id" : ObjectId("4fbb728d80db260988580e05"),
 
"titleFull" : "Foo, Inc",
 
"titleShort" : "Foo",
 
"countries" : [
     
ObjectId("4fba04ef80db260988f8b607"),
     
ObjectId("4fba05f880db260988cd5cfd") ],
 
"type" : "company"
}

And such class in ASP.NET MVC 4 Web API project:
public class Company
{
 
[BsonRepresentation(BsonType.ObjectId)]
 
public String id { get; set; }
 
public String titleFull { get; set; }
 
public String titleShort { get; set; }
 
//[BsonRepresentation(BsonType.ObjectId)]
 
//public String[] countries { get; set; } — not working
 
public ObjectId[] countries { get; set; }
 
public String type { get; set; }
}

When I'm sending GET request on /api/countries I receive JSON document (It's mvc deserialization):
{
 
"id": "4fba097e80db2609886ce7f2",
 
"titleFull": "Foo, LLC",
 
"titleShort": "Foo",
 
"countries": [
   
{
     
"_increment": 16299527
     
"_machine": 8444710
     
"_pid": 2440
     
"_timestamp": 1337591023
   
},
   
{
     
"_increment": 13458685
     
"_machine": 8444710
     
"_pid": 2440
     
"_timestamp": 1337591288
   
}
 
],
 
"type": "company"
}

Is there a way to do JSON response like this:
{
 
"id": "4fba097e80db2609886ce7f2",
 
"titleFull": "Foo, LLC",
 
"titleShort": "Foo",
 
"countries": ["4fba04ef80db260988f8b607","4fba05f880db260988cd5cfd"],
 
"type": "company"
}

craiggwilson

unread,
May 28, 2012, 6:33:00 PM5/28/12
to mongodb...@googlegroups.com
Yes, that is a known idiosyncrasy.  The issue is that the BsonRepresentation attribute is getting applied to the array and not the elements.  The best way to handle this right now is to use the BsonClassMap.Register method and set the serialization options for the member to a new instance of ArraySerializationOptions with a RepresentationSerializationOptions indicating how to serialize the items.

BsonClassMap.RegisterClassMap<Company>(cm =>
{
  cm.AutoMap();
  cm.MapMember(c => c.Countries)
    .SetSerializationOptions(new ArraySerializationOptions(new RepresentationSerializationOptions(BsonType.String)));
});

Robert Stam

unread,
May 28, 2012, 8:40:48 PM5/28/12
to mongodb...@googlegroups.com
You were on the right track, but there is a bug in the deserialization code. In the case of an array the [BsonRepresentation] attribute is in fact applied to the items and not the array.

I've created a JIRA ticket for this:

Максим Пономарев

unread,
May 28, 2012, 11:13:32 PM5/28/12
to mongodb...@googlegroups.com
Thank you Robert, I'll be track this ticket.

вторник, 29 мая 2012 г., 6:40:48 UTC+6 пользователь Robert Stam написал:

Максим Пономарев

unread,
May 28, 2012, 11:55:46 PM5/28/12
to mongodb...@googlegroups.com
Craig,

Could you give me an example how to use this code because all my attempts to implement It throws an errors.

I've tried this:
public class Company
{
  static Company() {
      BsonClassMap.RegisterClassMap<Company>( cm =>
      {
         cm.AutoMap();
         cm.MapMemeber(c => c.countries) //.GetMemberMap(c => c.countries)
            .SetSerializationOptions(
               new ArraySerializationOptions(
                  new RepresentationSerializationOptions(BsonType.String))); //(BsonType.ObjectId)));
      });
} [BsonRepresentation(BsonType.ObjectId)] public String id { get; set; } public String titleFull { get; set; } public String titleShort { get; set; } public String[] countries { get; set; } //public ObjectId[] countries { get; set; }

   public String type { get; set; }
}
and this (with standart Company class):
public IEnumerable<Company> GetAll()
{
   BsonClassMap.RegisterClassMap<Company>( cm =>
   {
      cm.AutoMap();
      cm.MapMemeber(c => c.countries) //.GetMemberMap(c => c.countries)
         .SetSerializationOptions(
            new ArraySerializationOptions(
               new RepresentationSerializationOptions(BsonType.String))); //(BsonType.ObjectId)));
   });
   var query = Query.EQ("type", "company");
   var companies = mongo.GetWhere<Company>("static", query);
   return companies;
}

вторник, 29 мая 2012 г., 4:33:00 UTC+6 пользователь craiggwilson написал:

Robert Stam

unread,
May 29, 2012, 12:11:18 AM5/29/12
to mongodb...@googlegroups.com
Aren't you just running into the issue in the JIRA I created?


Your exception is probably something like this, right?

System.IO.FileFormatException: An error occurred while deserializing the X field of class ConsoleApplication1.C: Cannot deserialize string from BsonType ObjectId.

Максим Пономарев

unread,
May 29, 2012, 12:23:03 AM5/29/12
to mongodb...@googlegroups.com
Yes, without  BsonClassMap.RegisterClassMap  I have the same exception:
System.IO.FileFormatException: An error occurred while deserializing the countries property of class SumoWebApi.Models.Company: Cannot deserialize string from BsonType ObjectId.

вторник, 29 мая 2012 г., 10:11:18 UTC+6 пользователь Robert Stam написал:
Aren't you just running into the issue in the JIRA I created?


Your exception is probably something like this, right?

System.IO.FileFormatException: An error occurred while deserializing the X field of class ConsoleApplication1.C: Cannot deserialize string from BsonType ObjectId.

Robert Stam

unread,
May 29, 2012, 12:57:15 AM5/29/12
to mongodb...@googlegroups.com
You're going to get the same exception whether you use an attribute on your array property or whether you use RegisterClassMap to set the ArraySerializationOptions until CSHARP-479 is fixed.

Максим Пономарев

unread,
May 29, 2012, 3:54:12 AM5/29/12
to mongodb...@googlegroups.com
That is, the using of  BsonClassMap.RegisterClassMap  is not the solution of my question?

вторник, 29 мая 2012 г., 10:57:15 UTC+6 пользователь Robert Stam написал:
You're going to get the same exception whether you use an attribute on your array property or whether you use RegisterClassMap to set the ArraySerializationOptions until CSHARP-479 is fixed.


вторник, 29 мая 2012 г., 10:57:15 UTC+6 пользователь Robert Stam написал:
You're going to get the same exception whether you use an attribute on your array property or whether you use RegisterClassMap to set the ArraySerializationOptions until CSHARP-479 is fixed.

craiggwilson

unread,
May 29, 2012, 7:30:06 AM5/29/12
to mongodb...@googlegroups.com
Yes, Robert is correct.  My apologies as I was misunderstanding the direction of our problem.  Until CSHARP-479 is fixed, then this bug will exist.  So, in the next day or two, you can pull our master and build it yourself, or you can wait until the next version is released.  We haven't set a date yet.

I assume you have a good reason for not using an actual ObjectId: perhaps this is getting pushed over WCF or something and you don't want to take a dependency on the MongoDB libraries.  I would suggest to you to use a Guid instead.  MongoDB handles guids just fine and the driver can autogenerate them as well.
Message has been deleted

Timofei Mironov

unread,
Jun 4, 2013, 4:12:57 AM6/4/13
to mongodb...@googlegroups.com
Hello.
Looks like the problem I have is very similar, but different a little.

I have Array of items where the property with [BsonRepresentation] attribute is stored inside of item.
The error I get is "A serialization options attribute of type BsonRepresentationAttribute cannot be used when the serializer is of type ObjectSerializer" when deserializing Provider instance.

public class Provider{
   public Item[] Items{set;get;};
}

public class Item{
   [BsonRepresentation(BsonType.ObjectId)]
   public object ItemKey{get;set;}
}

How to fix it?
P.S. I meet this case when upgrading my driver from 1.4.1 to 1.8.1 version.

Timofei Mironov

unread,
Jun 4, 2013, 4:29:27 AM6/4/13
to mongodb...@googlegroups.com
:-)

fixed with 

cm.AutoMap();
cm.MapMember(c => c.ItemKey).SetRepresentation(BsonType.ObjectId);

I don't know why it does not work with attribute.
Reply all
Reply to author
Forward
0 new messages