应使用 MongoDB.Driver 2.20+ 的 MongoClient 单例异步操作,注意连接串配置、URL 编码、超时设置,所有 Async 方法必须 await,实体映射按需注册,复杂更新优先评估 SQL 事务替代方案。

直接用 MongoClient 连接并操作集合,别碰过时的 MongoServer 或旧驱动 API —— 当前主流是 MongoDB.Driver 2.20+(.NET 6/7/8 兼容),老教程里一堆 GetDatabase 后再 GetCollection 的链式写法没问题,但容易漏掉异步等待、序列化配置或连接字符串权限问题。
连接字符串和 MongoClient 实例怎么配才不报错
常见错误是复制了 Atlas 的连接串却没替换 ,或者本地运行时用了 mongodb://localhost:27017 却没确认 mongod 进程在跑。MongoDB.Driver 不会主动抛出连接失败异常,直到你第一次执行 FindAsync 或 InsertOneAsync 才崩,错误信息通常是 System.TimeoutException 或 MongoConnectionException。
- 本地开发确保
mongod已启动(Windows 下检查服务,macOS/Linux 看ps aux | grep mongod) - Atlas 连接串必须 URL 编码用户名和密码,用
Uri.EscapeDataString处理,不能手填特殊字符 -
MongoClient是线程安全的,应全局单例复用,别每次操作都 new 一个 - 加超时:构造时传
new MongoClientSettings { ServerSelectionTimeout = TimeSpan.FromSeconds(5) }
InsertOneAsync 和 FindAsync 必须 await,否则卡死或返回空结果
这是 C# 新手最常踩的坑:写了 collection.InsertOneAsync(doc) 却没加 await,方法立刻返回未完成的 Task,后续逻辑继续执行,文档根本没插进去;或者用 .Result 强等,导致 UI 线程死锁(尤其 WinForms/WPF)。FindAsync 同理,不 await 就拿不到 IAsyncCursor,调 ToListAsync() 也会崩。
- 所有带
Async后缀的方法,必须在 async 方法体内用await调用 - 控制台程序入口可写
await MainAsync();,再把Main改成static async Task Main(string[] args) - 避免
.Wait()或.Result—— 在 ASP.NET Core 中可能引发请求线程饥饿 - 插入后想拿 ID?
var result = await collection.InsertOneAsync(doc); var id = result.InsertedId;
BsonClassMap.RegisterClassMap 什么时候必须调,什么时候可以跳过
如果你的实体类字段名和 MongoDB 字段名一致(比如 public string Name { get; set; } 对应 BSON 字段 "name"),且没用特殊类型(如 DateTimeOffset、字节数组、嵌套泛型),那默认序列化器能搞定,不用注册映射。但一旦出现字段名不匹配、需要忽略某属性、或自定义日期格式,就必须提前注册。
- 注册必须在首次使用该类型前完成,通常放在
Program.cs或Startup.ConfigureServices开头 - 忽略字段:用
BsonIgnore特性比在RegisterClassMap里写IgnoreMember(x => x.CreatedBy)更直观 - 重命名字段:
SetElementName(x => x.FullName, "full_name"),注意大小写敏感 - 时间序列场景下,
DateTime默认存为 UTC,若业务强依赖本地时区,得用BsonDateTimeOptions配置
真正麻烦的是嵌套文档更新和原子性操作——比如“给用户订单数组追加一条记录并更新总金额”,这得用 UpdateOneAsync 配合 Builders,不是简单改个对象再 ReplaceOneAsync 就行。字段级更新逻辑一旦复杂,BSON 表达式很快变得难读,这时候该考虑是否真需要 MongoDB 的灵活性,还是换成带事务的 SQL 方案更稳。











