How to Insert document to MongoDB and return the same document or it's ID back using InsertOneAsync in C# .Net [duplicate]
Asked Answered
S

2

6

I'm writing a generic method to act like data access layer to insert document to MongoDB using C# .Net. My method looks like below. Collection here is a MongoCollection retrieved from MongoDB.

public async T Create(T entity){
await Collection.InsertOneAsync(entity);
}

I want to return the entity inserted or it's ID which is auto generated by MongoDB back. InsertOneAsync method is returning a task. I tried changing it as below. But its's return type is void.

Collection.InsertOneAsync(entity).GetAwaiter().GetResult();

Is there a way to get the id or entity back using InsertOneAsync method. I'm using MongoDB driver for C#.

Sisal answered 27/4, 2018 at 19:5 Comment(0)
F
6

Ids in MongoDB are generated on the client side.

If the document does not specify an _id field, then MongoDB will add the _id field and assign a unique ObjectId for the document before inserting. Most drivers create an ObjectId and insert the _id field, but the mongod will create and populate the _id if the driver or application does not.

In you case you can generate ObjectIds manually and return them from your method (using ObjectId.GenerateNewId()) or return entire object since MongoDB driver will set proper _id value if you use [BsonId] attribute

public async Task<T> Create(T entity) where T:class
{
    await Collection.InsertOneAsync(entity);
    return entity;
}

And pass a type parameter like:

public class MyClass
{
    [BsonId]
    public ObjectId Id { get; set; }
    //other properties
}
Fayfayal answered 27/4, 2018 at 19:39 Comment(5)
so if client does not set id, InsertOneAsync will update the entity's id property? and when we return the same entity, it will be returned with generated id?Sisal
@Sisal exactlyFayfayal
this is not working as you said. It is just returning what we passed. The generated id is not returned.Sisal
@Sisal I've tested this really quickly in Console App using driver v 2.5.0 and following code: var result = p.Create(new MyClass()).GetAwaiter().GetResult(); and I'm getting generated ObjectId under Id property. Could you post your code ?Fayfayal
My bad.. you are right..Sisal
W
2

A good solution consists in letting the client generate the _id for you.

public class MyEntity
{
    [BsonId(IdGenerator = typeof(ObjectIdGenerator))]
    public ObjectId Id { get; set; }

    public string SomeStringProperty { get; set; }
    public DateTime SomeDateTimeProperty { get; set; }
}

The _id is generated whenever an entity with null _id is inserted in the database, and it's up to the driver to provide an _id value before insertion.

In case you don't want to reference MongoDB library in your domain model (so as I prefer) you might simply define your entity as follows.

public class MyEntity
{
    public string Id { get; set; }

    public string SomeStringProperty { get; set; }
    public DateTime SomeDateTimeProperty { get; set; }
}

Then, use this code directly in the persistence layer to map your entity with the database.

BsonClassMap.RegisterClassMap<MyEntity>(cm =>
{
    cm.AutoMap();
    cm.MapIdMember(c => c.Id)
        .SetIdGenerator(StringObjectIdGenerator.Instance)
        .SetSerializer(new StringSerializer(BsonType.ObjectId));
});

string Ids are easier to be handled in the code, though this way they are mapped as ObjectId within the database.

Be careful: if you use the async version of InsertOne() method, you must wait for the insert to be at least started before getting the _id value set by the driver.

Workhorse answered 27/4, 2018 at 19:57 Comment(1)
Thank you @Workhorse for the detailed answer.Sisal

© 2022 - 2024 — McMap. All rights reserved.