MongoDB C# Driver中SetOnInsert误区:如何仅插入时设置Guid型_id
解决MongoDB FindOneAndUpdate仅在插入时设置_id的问题
问题根源
你遇到的问题主要来自两个点:一是字符串形式的filter存在语法错误,导致每次都匹配不到已有文档,触发upsert生成新_id;二是实体类的_id字段可能配置了自动生成规则,覆盖了你SetOnInsert的赋值。
修正方案
1. 正确定义实体类
确保_id字段不配置自动生成规则,让代码手动控制赋值:
public class TestClass { [BsonId] public Guid Id { get; set; } public string Path { get; set; } public string Name { get; set; } }
2. 使用强类型Filter避免语法错误
放弃字符串形式的filter,改用强类型构建器,确保匹配逻辑准确:
// 序列化配置保持不变 BsonDefaults.GuidRepresentationMode = GuidRepresentationMode.V3; BsonSerializer.RegisterSerializer<Guid>(new GuidSerializer(GuidRepresentation.Standard)); // 强类型构建filter,精准匹配Path字段 FilterDefinition<TestClass> filter = Builders<TestClass>.Filter.Eq(t => t.Path, "a.b.c.d"); var updateBuilder = Builders<TestClass>.Update; var update = updateBuilder .SetOnInsert(t => t.Id, Guid.NewGuid()) // 仅在插入新文档时设置_id .Set(t => t.Path, "a.b.c.d") // 插入/更新都设置Path .Set(t => t.Name, "c.d"); // 插入/更新都设置Name var options = new FindOneAndUpdateOptions<TestClass> { IsUpsert = true, ReturnDocument = ReturnDocument.After }; var result = collNamespace.FindOneAndUpdate<TestClass>(filter, update, options);
3. 可选:给Path字段加唯一索引
为了避免重复创建相同Path的文档,同时提升查询匹配效率,给Path字段添加唯一索引:
collNamespace.Indexes.CreateOne(new CreateIndexModel<TestClass>( Builders<TestClass>.IndexKeys.Ascending(t => t.Path), new CreateIndexOptions { Unique = true } ));
关键说明
SetOnInsert确实只会在upsert触发插入操作时生效,更新已有文档时不会修改_id;- 之前的字符串filter存在引号嵌套错误(
"{ Path: "a.b.c.d" }"),导致MongoDB无法正确解析匹配条件,每次都执行插入; - 实体类的
_id如果配置了GuidGenerator这类自动生成器,会覆盖SetOnInsert的赋值,所以必须去掉自动生成配置。
内容的提问来源于stack exchange,提问作者GreenEyedAndy
相关产品推荐
相关产品推荐

