Search code examples
c#mongodbmongodb-.net-driver

How to create ids for subdocuments in Mongodb with c#


I'm trying to automatically create ids for subdocuments in mongodb.

I have the following classes:

public class Test
{
    public string Id {get;set;}
    public List<SubTest> SubTestList{get;set;}

    public Test()
    {
        SubTestList = new List<SubTest>();
    }
}

public class SubTest
{
    public string Id {get;set;}
    public string Name {get;set;}
}

Another Dll which will be used to get stored in MongoDB is like this (for decoupling reasons its an own dll):

public class TestMongo : Test
{
    static TestMongo()
    {
        //using this instead of attributes above every needed property. will avoid dependencies to mongodb.
        BsonClassMap.RegisterClassMap<Test>(cm =>
        {
            cm.AutoMap();

            //register property "Id" to be the mongodb.
            cm.SetIdMember(cm.GetMemberMap(c => c.Id).SetRepresentation(BsonType.ObjectId));

            //Will generate an Id and set the Id-Property which is a string in this class.
            cm.IdMemberMap.SetIdGenerator(StringObjectIdGenerator.Instance);
        });
    }
}

I'm adding the attributes programmatically to the properties to make sure that I don't have a dependency to Mongo when using the Test-class.

Now I need to autocreate a Id for each created SubTest-Element. I tried to add another map within the TestMongo-Constructor but it didn't work:

...
BsonClassMap.RegisterClassMap<SubTest>(cm =>
{
    cm.AutoMap();

    //register property "Id" to be the mongodb.
    cm.SetIdMember(cm.GetMemberMap(c => c.Id).SetRepresentation(BsonType.ObjectId));

    //Will generate an Id and set the Id-Property which is a string in this class.
    cm.IdMemberMap.SetIdGenerator(StringObjectIdGenerator.Instance);
 });

Of course I could iterate through all SubTest-Elements before writing it to mongo but I would prefer to let the c#-driver do that for me.

Is there a way I can do this?


Solution

  • This way uses custom object serialzer for mongo:

    1- write the serializer:

    public class TestSerialzer : IBsonSerializer
    {
        public object Deserialize(BsonReader bsonReader, Type nominalType, IBsonSerializationOptions options)
        {
            return BsonSerializer.Deserialize<Test>(bsonReader);
        }
    
        public object Deserialize(BsonReader bsonReader, Type nominalType, Type actualType, IBsonSerializationOptions options)
        {
            throw new NotImplementedException();
        }
    
        public IBsonSerializationOptions GetDefaultSerializationOptions()
        {
            throw new NotImplementedException();
        }
    
        public void Serialize(BsonWriter bsonWriter, Type nominalType, object value, IBsonSerializationOptions options)
        {            
            var test = (Test)value;
            bsonWriter.WriteStartDocument();
    
            if (string.IsNullOrEmpty(test.Id)) test.Id = ObjectId.GenerateNewId().ToString();
    
            bsonWriter.WriteString("_id", test.Id);
    
            foreach (var nestedObj in test.SubTestList)
            {
                if (string.IsNullOrEmpty(nestedObj.Id)) nestedObj.Id = ObjectId.GenerateNewId().ToString();
            }
    
            bsonWriter.WriteStartArray("SubTestList");
            BsonSerializer.Serialize(bsonWriter, test.SubTestList);
    
            bsonWriter.WriteEndArray();
            bsonWriter.WriteEndDocument();
        }
    }
    

    register the serializer at you app startup:

    BsonSerializer.RegisterSerializer(typeof(Test), new TestSerialzer());
    

    and for a test object as below:

    var test = new Test
    {
        SubTestList = new List<SubTest>
        {
          new SubTest
          {
              Name = "Name1",
          },
          new SubTest
          {
            Name  = "Name2",
          },
        },
    };
    collection.Insert(test);
    

    you will have:

    {
        "_id" : "54ad5b25e8b07a214c390ccf",
        "SubTestList" : [ 
            [ 
                {
                    "_id" : "54ad5b25e8b07a214c390cd0",
                    "Name" : "Name1"
                }, 
                {
                    "_id" : "54ad5b25e8b07a214c390cd1",
                    "Name" : "Name2"
                }
            ]
        ]
    }