Uploaded image for project: 'C# Driver'
  1. C# Driver
  2. CSHARP-648

BsonClassMap sometimes maps Id to _id when you don't want it to

    • Type: Icon: Bug Bug
    • Resolution: Done
    • Priority: Icon: Major - P3 Major - P3
    • 1.8
    • Affects Version/s: 1.7
    • Component/s: None
    • None

      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.

            Assignee:
            robert@mongodb.com Robert Stam
            Reporter:
            robert@mongodb.com Robert Stam
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: