You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 16:48:18