[CSHARP-2415] Different behavior between Upsert and Insert with default ObjectId Created: 11/Oct/18  Updated: 27/Oct/23  Resolved: 11/Oct/18

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

Type: Task Priority: Major - P3
Reporter: Sun Yu Assignee: Robert Stam
Resolution: Works as Designed Votes: 0
Labels: question
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

I found the behavior between Insert and Upsert is differenct when I use C# Driver v2.7. Something like this:

An entity such as:

// code placeholder
public class Person
{
    public ObjectID _id { get; set; }
    public string Name { get; set; }
}

 

When I use Insert Method:

// code placeholder
var collection = db.GetCollection<Person>(collectionName);
Person entity = new Person();
entity.Name = "Peter";
 
collection.InsertOne(entity);

 

it's correctly stored in DB with generated ObjectId like this:

// code placeholder
{
  "_id":"5bb67b8b8d3632037461b621",
  "Name":"Peter"
}

 

But when I use Upsert such as:

// code placeholder
......
 
collection.ReplaceOne(item => false, entity, new UpdateOptions() { IsUpsert = true });

 

it's stored with default ObjectId (all zero) like:

// code placeholder
{
  "_id":"000000000000000000000000",
  "Name":"Peter"
}

 

Is it the reasonable behavior difference between Upsert and Insert ?



 Comments   
Comment by Robert Stam [ 11/Oct/18 ]

This is expected behavior. The difference is that in the InsertOne case it is the driver that is responsible for generating the ObjectId, whereas in the ReplaceOne (with upsert) case it is the server that is responsible for generating the ObjectId if necessary.

However:

  1. The driver generates an _id value if the existing _id value is equal to the default value (which in the case of ObjectId is all zeroes)
  2. The server generates an _id value if and only if the _id value is missing

In your ReplaceOnce example the entity value you are sending to the server is not missing, it is all zeros so the server does not generate the _id value because one is already present (and has a value of all zeros).

If you actually want ReplaceOne to generate the _id server side you should configure your POCO so that when the _id value is all zeros it is not serialized.

public class Person
{
    [BsonIgnoreIfDefault]
    public ObjectID _id { get; set; }    
    public string Name { get; set; }
}

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