Using MongoDb _Id field with C# POCOs

When using official C# mongo driver any field with name ‘Id’ and type “ObjectId” is mapped to _Id field in mongo db.What that means is that If you don’t supply some value for “Id” field default value would be generated (using default Id Generator)and the same will be deserialized into Id field of your POCO while fetching the data.

Lets take a simple POCO class as shown below .

 public class Post
    {
        public ObjectId Id { get; set; }
        public string Title { get; set; }
        public string Tags { get; set; }
        public string Description { get; set; }
    }

Saving this class without providing value for Id field would automatically generate the object id value as shown below.

image

But for most of the real world applications you cannot constrain yourself with the restriction of having type of Id field as “ObjectId” and name as “Id”.

In these cases we need to do few extra things to ensure that mapping and id generation happens properly.

Mapping a property to _Id field

We can use any property of our POCO class as Id property.Lets see what happens when I rename Id field to PostId.

public class Post
    {
        public ObjectId PostId { get; set; }
        public string Title { get; set; }
        public string Tags { get; set; }
        public string Description { get; set; }
    }

Trying to save this POCO we get following error “System.InvalidOperationException: No IdGenerator found.”   To map this property we can use BsonId  attribute as shown below.

    public class Post
    {
        [BsonId]
        public ObjectId PostId { get; set; }
        public string Title { get; set; }
        public string Tags { get; set; }
        public string Description { get; set; }
    }

And it will map to _Id value correctly.

Changing type of Id Property

Lets say I want to have my Id field as a string i.e. I want to have Id saved as ObjectId in mongodb but should be string in my POCO class.If I try this with current code again I will get same error i.e. “System.InvalidOperationException: No IdGenerator found.” To make this work you need to pass a parameter to BsonId attribute as shown below.This specifies the IdGenerator to use which in our case is StringObjectIdGenerator.

    public class Post
    {
        [BsonId(IdGenerator=typeof(StringObjectIdGenerator))]
        public string PostId { get; set; }
        public string Title { get; set; }
        public string Tags { get; set; }
        public string Description { get; set; }
    }

This is an inbuilt id generator which is used for string represented as ObjectId in MongoDb. MongoDb provides couple of inbuilt Id Generators as shown below.

  • BsonObjectIdGenerator
  • CombGuidGenerator
  • GuidGenerator
  • NullIdChecker
  • ObjectIdGenerator
  • StringObjectIdGenerator
  • ZeroIdChecker<T>

For more details visit this link.

Custom Id Generator

Finally there may be situations where you want to generate your own ids.This can be accomplished by implementing a custom id generator.Let say we want to generate  custom ids which will have following format <MyApplicationName>_<GUID>.

To create custom id generator we need a class that implement IIdGenerator interface and use that as Id Generator type.

Custom Id Generator:

 public class BlogIdGenerator : IIdGenerator
    {

        public object GenerateId(object container, object document)
        {

            return "Blog_" + Guid.NewGuid().ToString();
        }

        public bool IsEmpty(object id)
        {
            return id == null || String.IsNullOrEmpty(id.ToString());
        }
    }

Using Id Generator in our POCO class:

 public class Post
    {
        [BsonId(IdGenerator = typeof(BlogIdGenerator))]
        public string PostId { get; set; }
        public string Title { get; set; }
        public string Tags { get; set; }
        public string Description { get; set; }
    }

Results:

image

I had to struggle initially  to understand how all these scenarios worked (may be because I didn’t pay enough attention to basics).Hope this post will  help other to get started smoothly with these basic concepts.

Additional Resources

MongoDb official documentation
Pluralsight course on Using MongoDB with ASP.NET MVC
C# and .Net MongoDb driver

Tagged on: ,

7 thoughts on “Using MongoDb _Id field with C# POCOs

  1. vn

    great post saved me a bunch of time. Took a while to find this great info. I feel its underdiscussed.

  2. ilker

    Thanks for information.
    Do have to depend on mongo db driver for the Id property.
    Is there a way just leave POCO classes without any references.

    1. Ivo

      No need to reference db driver from an object being serialized to express which property is identity.
      Just use BsonClassMap from your initialization code:

      var classMap = new BsonClassMap(typeof (TModel))
      .MapIdField(“Id”)
      .SetIdGenerator(StringObjectIdGenerator.Instance)
      .ClassMap;

      BsonClassMap.RegisterClassMap(classMap);

      You could also use generic version of the class to avoid having to write “Id” as a string.

      1. Steve Ferguson

        Thank you for this. I wasn’t thrilled about adding MongoDB.Bson as a dependency on my otherwise “clean” shared domain library.

  3. kartik

    How will this work in case of concurrent inserts and say you are using sequential integers (1, 2, 3,…) for ID ???

Leave a Reply to Jagmeet Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.