[CSHARP-648] BsonClassMap sometimes maps Id to _id when you don't want it to Created: 14/Dec/12  Updated: 20/Mar/14  Resolved: 04/Jan/13

Status: Closed
Project: C# Driver
Component/s: None
Affects Version/s: 1.7
Fix Version/s: 1.8

Type: Bug Priority: Major - P3
Reporter: Robert Stam Assignee: Robert Stam
Resolution: Done Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

BsonClassMap sometimes maps a class member to the field "_id" when you don't want it to. Suppose you wanted to produce the following document:

{
    _id : 1,
    User : { Id : 2, Name : "John" }
}

using these classes:

public class C
{
    public int Id;
    public User User;
}
 
public class User
{
    public int Id;
    public string Name;
}

The problem is that it produces this instead:

{
    _id : 1,
    User : { _id: 2, Name : "John" }
}

The reason is that the User class mapped it's Id member to the field "_id" instead of to "Id". That behavior is the right thing to do for class C which is used as the type of the document stored in the collection, but is not necessarily the right thing to do with class User, which is stored as an embedded document inside C.

The root of the problem is that the driver doesn't know if class User is going to be used as a root document or as an embedded document, so it processes all classes the same, including the rule that a member called "Id" will be chosen to be mapped to the (supposedly) required "_id" field.

The following potential workaround does not work:

public class User
{
    [BsonElement("Id")]
    public int Id;
    public string Name;
}

At least not now, because the process of selecting a member to be mapped to the "_id" field happens after the [BsonElement("Id")] attribute has been processed and overrides it.

The following workaround does work:

var noIdConventions = new ConventionProfile();
noIdConventions.SetIdMemberConvention(new NamedIdMemberConvention()); // no names
BsonClassMap.RegisterConventions(noIdConventions, t => t == typeof(User));

Which works by suppressing the selection of the "Id" member as the one to be used as the MongoDB _id field.

This description does not propose a fix, but some things to consider are:

1. Perhaps the presence of [BsonElement("Id")] could suppress the mapping to _id
2. Perhaps there could be some other way to tell the driver not to do the _id mapping, like an attribute on the class telling the driver that this class will be used as an embedded document exclusively and does not have an _id field

For example:

[BsonNoId]
public class User
{
    public int Id;
    public string Name;
}

Suggestions welcome.



 Comments   
Comment by auto [ 04/Jan/13 ]

Author:

{u'date': u'2013-01-04T15:53:43Z', u'email': u'robert@10gen.com', u'name': u'rstam'}

Message: CSHARP-648: Provide a way to suppress the mapping of Id to _id.
Branch: master
https://github.com/mongodb/mongo-csharp-driver/commit/4b552a6a810709fb396155dc41ea8f972b15c824

Comment by Craig Wilson [ 26/Dec/12 ]

Still not sure how to get around this, but it manifests itself differently now that the conventions are rewritten. For instance, unmapping an Id Member will prevent the member from having it's element name changed to _id. This is because the element name change happens at freeze as opposed to at assignment.

Generated at Wed Feb 07 21:37:26 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.