[CSHARP-804] Not ignoring readonly "id fields NamedIdMemberConvention leads to unique key violation Created: 16/Aug/13  Updated: 18/Sep/14  Resolved: 18/Sep/14

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

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


 Description   

The NUnit test below will throw a E1100 duplicate key error

 
using MongoDB.Bson;
using MongoDB.Driver;
using NUnit.Framework;
 
namespace MongoDB.BsonUnitTests.Jira
{
    [TestFixture]
    public class ReadOnlyIdTests
    {
        public class ReadOnlyIdFieldClass
        {
            public readonly int Id = 1;
            public int id = 1;
        }
 
 
        [Test]
        public void TestSerialization()
        {
            var obj1 = new ReadOnlyIdFieldClass();
            obj1.id = 1;
            var obj2 = new ReadOnlyIdFieldClass();
            obj2.id = 2;
            var client = new MongoClient();
            var coll = client.GetServer().GetDatabase("foo").GetCollection<ReadOnlyIdFieldClass>("bar");
            coll.Insert(obj1);
            coll.Insert(obj2);
        }
    }
}

The fix is to either skip readonly fields as part of NameIdMemberConvention or implement it as a MemberMapConvention



 Comments   
Comment by Robert Stam [ 18/Sep/14 ]

This actually works as designed. I'll explain why below and slightly change the example so that it works.

First, I would observe that it is bad practice to have two members that differ only in case, so having "Id" and "id" in the same class is a bad idea. However, the driver does support that, and is identifying the "Id" field as the _id field of the document and therefore mapping it to the "_id" element name. The "id" field in turn is mapped to the "id" element name.

Second, you can't really have an immutable Id unless you also have a constructor to set it (otherwise all your documents will have the same _id, which of course leads to duplicate key exceptions when you attempt to insert them to the database). So let's alter the class slightly:

public class ReadOnlyIdFieldClass
{
    public readonly int Id;
    public int id;
 
    public ReadOnlyIdFieldClass(int value)
    {
        Id = value;
    }
}

and now let's alter the code that inserts the documents slightly so that each document is given a different _id value:

var obj1 = new ReadOnlyIdFieldClass(1);
obj1.id = 123;
var obj2 = new ReadOnlyIdFieldClass(2);
obj2.id = 456;
 
collection.Insert(obj1);
collection.Insert(obj2);

Which now executes without a duplicate key exception and inserts the following into the database:

> db.test.find()
{ "_id" : 1, "id" : 123 }
{ "_id" : 2, "id" : 456 }
>

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