首页 > 解决方案 > C# MongoDB 从填充模型更新定义

问题描述

我如何结合类型 C# 填充模型和 mongo 语言来创建更新请求?

我试试这个但得到类型错误:

 var update = new ObjectUpdateDefinition<User>(user) & Builders<User>.Update.Inc(f => f.FindCount, 1);

全码:

            var user = new Model
            {
                Email = email,
                Language = language,
                Password = password,
                // +17 fields
            };
            
            // how i can convert all fields to set? and join with query Inc (like AllFieldToSet)? 
            var update = user.AllFieldToSet() & Builders<User>.Update.Inc(f => f.FindCount, 1);
            
            Models.FindOneAndUpdate<Model>(
             f => f.Email == email, 
             update, 
             new FindOneAndUpdateOptions<Model> {IsUpsert = true});

标签: c#mongodbmongodb-querymongodb-.net-driver

解决方案


首先,我会开始问你为什么一次更新这么多字段,这会对性能和可伸缩性产生重大影响,尤其是当你的集合涉及索引、复制和/或分片时。每当您必须更新索引字段时,它也需要更新索引。

有多种解决方案:

ReplaceOne: Inc 只增加值,这可以在模型中手动完成:FindCount++

手动构建更新操作符:只需使用他们提供的构建器手动构建

使用反射编写你自己的扩展我个人喜欢类型安全,但你可以使用我编写的这个扩展(你只需要扩展它并构建空检查等)

public static class UpdateBuilderExtensions
{
    public static UpdateDefinition<TDocument> SetAll<TDocument, TModel>(this UpdateDefinition<TDocument> updateBuilder, TModel value, params string[] excludeProperties)
    {
        foreach (var property in value.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(x => excludeProperties?.Contains(x.Name) == false))
            updateBuilder = Builders<TDocument>.Update.Combine(updateBuilder.Set(property.Name, property.GetValue(value)));

        return updateBuilder;
    }
}

它的用法:您必须排除已经设置的属性,并且必须排除 BsondId 字段(如果您不手动设置)

var update = Builders<User>.Update.Inc(x => x.FindCount, 1).SetAll(model, nameof(model.Id), nameof(model.FindCount));
Models.UpdateOne(x => x.Email== "some-email", update, new UpdateOptions
{
IsUpsert = true
});

推荐阅读