Search code examples
mongodbasp.net-coremongodb-.net-driver

Wrong document ID after Save/Read


In an ASP.NET Core application (with MongoDb) I am trying to retrieve a document that I just created before.

Here is my document (POCO):

public class Person
{
    [BsonId]
    public ObjectId Id { get; }

    public string Name { get; set; }

    public Person()
    {
        this.Id = ObjectId.GenerateNewId();
    }
}

My ASP.NET Core controller:

public class HomeController : Controller
{
    private readonly IMongoDbContext _context;

    public HomeController(IMongoDbContext context)
    {
        _context = context;
    }

    public async Task<IActionResult> Index()
    {
        var repository = new Repository(_context);

        var personX = await repository.CreatePersonAsync(name: "John created at " + DateTime.Now.ToFileTimeUtc());

        var personY = await repository.GetPersonByIdAsync(personX.Id);

        return View();
    }
}

Finally in my repository class:

   public async Task<Person> CreatePersonAsync(string name)
    {
        var person = new Person() { Name = name };

        var filter = Builders<Person>.Filter.Eq("_id", person.Id);

        var saveResult = await this.PersonCollection.ReplaceOneAsync(filter, person, new UpdateOptions { IsUpsert = true });

        return person;
    }

    public async Task<Person> GetPersonByIdAsync(ObjectId id)
    {
        var person = await this.PersonCollection.Find(x => x.Id.Equals(id)).FirstOrDefaultAsync();

        return person;
    }

When debugging my application in Visual Studio 2017 CE:

  1. personX: Id = {5a3b81ceff702421e00c5c7e}, Name = "John created at 131583228941663577"
  2. personY: Id = {5a3b81ceff702421e00c5c7f}, Name = "John created at 131583228941663577"

While the Name values are identical, the Ids are slightly different. Why? What am I missing?

It's probably something about async/await that I messed up, because everything works fine if I do everything synchronously.

Thanks for any help, guys!

ASP.NET Core 2, MongoDb.Driver 2.5


Solution

  • The problem is in your Person class. Id property does not have a setter, it's just initialized in constructor with value of ObjectId.GenerateNewId(). That's why when GetPersonByIdAsync() is called, MongoDB driver could not fill Id property with value stored in the database and it's filled with new id generated with ObjectId.GenerateNewId().

    To fix the problem add a public setter to Id property. I also suggest not to fill it in constructor. Just fill it when you create new Person instance for adding to the database:

    public class Person
    {
        [BsonId]
        public ObjectId Id { get; set; }
    
        public string Name { get; set; }
    }
    
    public async Task<Person> CreatePersonAsync(string name)
    {
        var person = new Person()
        {
            Id = ObjectId.GenerateNewId(),
            Name = name,
        };
    
        var filter = Builders<Person>.Filter.Eq("_id", person.Id);
    
        var saveResult = await this.PersonCollection.ReplaceOneAsync(filter, person, new UpdateOptions { IsUpsert = true });
    
        return person;
    }