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

C#使用MongoDB.Driver时无法访问MongoCollection类及Save方法

问题根因

MongoDB官方C#驱动从2.0版本开始已经完全移除了1.x版本中存在的MongoCollection类以及对应的Save()方法,你查阅到的提到Save()的文档均为旧版驱动的遗留内容,新版驱动的IMongoCollection接口本身没有内置Save()实现,这就是你IDE报错、找不到对应定义的核心原因。
如果一定要使用原生MongoCollection类和Save()方法,只能将C#驱动版本回退到1.x系列,但该版本已经停止维护多年,兼容性和性能都较差,不推荐使用。

通用Save()扩展方法实现方案

你可以自行给IMongoCollection编写扩展方法模拟旧版Save()的逻辑:自动判断文档_id是否为默认值,是则走插入逻辑,否则走基于_id的全量替换逻辑,完全符合你封装通用IMongoRepository、无需额外参数即可完成新增/更新的需求,实现代码如下:

using MongoDB.Driver;
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
using System.Reflection;

public static class MongoCollectionExtensions
{
    /// <summary>
    /// 模拟旧版Save方法,自动判断新增或更新
    /// </summary>
    public static void Save<TDocument>(this IMongoCollection<TDocument> collection, TDocument document)
        where TDocument : class
    {
        // 查找文档的Id字段,优先找标记了[BsonId]的属性,其次找名为Id的属性
        PropertyInfo idProperty = typeof(TDocument).GetProperties()
            .FirstOrDefault(p => p.GetCustomAttributes(typeof(BsonIdAttribute), true).Any())
            ?? typeof(TDocument).GetProperty("Id");
            
        if (idProperty == null)
        {
            throw new InvalidOperationException("目标文档未定义Id字段,请添加[BsonId]标记或命名属性为Id");
        }

        object idValue = idProperty.GetValue(document);
        // 判断Id是否为默认值(覆盖常用Id类型的默认情况)
        bool idIsDefault = idValue switch
        {
            null => true,
            ObjectId objectId => objectId == ObjectId.Empty,
            string strId => string.IsNullOrWhiteSpace(strId),
            Guid guidId => guidId == Guid.Empty,
            _ => EqualityComparer<object>.Default.Equals(idValue, Activator.CreateInstance(idProperty.PropertyType))
        };

        if (idIsDefault)
        {
            collection.InsertOne(document);
        }
        else
        {
            FilterDefinition<TDocument> idFilter = Builders<TDocument>.Filter.Eq("_id", idValue);
            collection.ReplaceOne(idFilter, document, new ReplaceOptions { IsUpsert = true });
        }
    }

    /// <summary>
    /// 异步版本Save方法
    /// </summary>
    public static async Task SaveAsync<TDocument>(this IMongoCollection<TDocument> collection, TDocument document, CancellationToken cancellationToken = default)
        where TDocument : class
    {
        PropertyInfo idProperty = typeof(TDocument).GetProperties()
            .FirstOrDefault(p => p.GetCustomAttributes(typeof(BsonIdAttribute), true).Any())
            ?? typeof(TDocument).GetProperty("Id");
            
        if (idProperty == null)
        {
            throw new InvalidOperationException("目标文档未定义Id字段,请添加[BsonId]标记或命名属性为Id");
        }

        object idValue = idProperty.GetValue(document);
        bool idIsDefault = idValue switch
        {
            null => true,
            ObjectId objectId => objectId == ObjectId.Empty,
            string strId => string.IsNullOrWhiteSpace(strId),
            Guid guidId => guidId == Guid.Empty,
            _ => EqualityComparer<object>.Default.Equals(idValue, Activator.CreateInstance(idProperty.PropertyType))
        };

        if (idIsDefault)
        {
            await collection.InsertOneAsync(document, null, cancellationToken);
        }
        else
        {
            FilterDefinition<TDocument> idFilter = Builders<TDocument>.Filter.Eq("_id", idValue);
            await collection.ReplaceOneAsync(idFilter, document, new ReplaceOptions { IsUpsert = true }, cancellationToken);
        }
    }
}

使用方式

在项目中引入上述扩展类后,即可直接通过IMongoCollection实例调用Save()或SaveAsync()方法,无需额外传参即可完成基于_id的新增/更新操作。
你遇到的IDE报错参考如下:
调用Save()时的报错信息

内容的提问来源于stack exchange,提问作者Musab Marzouque

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 23:57:03