C# MongoDB Driver 2.21 ReplaceOne Upsert时Id自动生成异常问题
解决MongoDB Driver 2.21 Upsert时自动生成ObjectId的问题
针对你遇到的Upsert操作插入000000000000000000000000(ObjectId.Empty)的问题,核心原因是ReplaceOneAsync执行Upsert时,若传入文档包含_id字段(哪怕是默认Empty值),MongoDB会直接使用该值,而非自动生成。以下是具体的解决方法:
1. 修正类映射配置(最推荐)
你之前的配置存在拼写错误,导致忽略默认值的规则未生效,需按以下方式修正:
方式一:使用特性标记
在Id字段上添加正确的特性,明确主键并忽略默认值:
[BsonId] [BsonIgnoreIfDefault] public ObjectId Id { get; set; }
[BsonId]:告诉MongoDB该字段是文档主键[BsonIgnoreIfDefault]:当字段值为ObjectId.Empty时,序列化时忽略该字段,让MongoDB自动生成新的_id
方式二:使用Fluent类映射
如果用代码配置映射,注意修正方法名拼写(你之前写的SetIgnoreIfDefaault少了一个u):
BsonClassMap.RegisterClassMap<TStorage>(m => { m.AutoMap(); // 明确映射为主键,并设置忽略默认值 m.MapIdMember(e => e.Id) .SetIgnoreIfDefault(true); });
2. 代码层面手动处理(备选方案)
如果上述配置仍未生效,可以在执行Upsert前手动处理文档:
var m = _mapper.Map<TStorage>(s); FilterDefinition<TStorage> filter; var doc = m.ToBsonDocument(); if (m.Id == ObjectId.Empty) { // 构造永远匹配不到的过滤条件,触发Upsert插入逻辑 filter = Builders<TStorage>.Filter.Eq(e => e.Id, ObjectId.Empty); // 移除文档中的Empty _id字段,让MongoDB自动生成 doc.Remove("_id"); } else { // 正常匹配已有文档执行更新 filter = Builders<TStorage>.Filter.Eq(e => e.Id, m.Id); } var result = await collection.ReplaceOneAsync(filter, doc, new ReplaceOptions { IsUpsert = true });
为什么之前的尝试无效?
- 特性名错误:不存在
[BsonIgnoreIdDefault]这个特性,正确名称是[BsonIgnoreIfDefault] - Fluent映射方法名拼写错误:
SetIgnoreIfDefaault应为SetIgnoreIfDefault,拼写错误导致配置未生效 - 未明确标记主键:如果没有
[BsonId]或MapIdMember,MongoDB序列化器可能不会正确应用忽略默认值的规则
内容的提问来源于stack exchange,提问作者herme 0
相关产品推荐
相关产品推荐

