如何在C#中为内存对象应用MongoDB风格的更新补丁?
如何将MongoDB风格的更新定义应用到C#内存对象
问题场景
现有C#内存中的Employee对象,通过MongoDB驱动的Builders<Employee>.Update创建了更新定义,生成了类似{ "$set" : { "LastName" : "ln1", "FirstName" : "another" } }的更新指令,但无真实数据库,需要直接将该更新应用到内存对象上。示例代码如下:
using MongoDB.Bson.Serialization; using MongoDB.Driver; class Program { class Employee { public string LastName { get; set; } = string.Empty; public string FirstName { get; set; } = string.Empty; } public static void Main(string[] args) { Employee employee = new Employee() { LastName = "ln", FirstName = "test" }; var def = Builders<Employee>.Update.Set("LastName", "ln1"); def = def.Set("FirstName", "another"); var registry = BsonSerializer.SerializerRegistry; var serializer = registry.GetSerializer<Employee>(); var patch = def?.Render(serializer, registry).ToString() ?? string.Empty; //TODO: 如何将此“补丁”应用到employee对象? } }
解决方案
MongoDB .NET驱动未直接提供内存对象更新API,但可通过以下两种方式实现需求:
方法一:基于BsonDocument序列化/反序列化(推荐)
借助MongoDB的Bson序列化机制,将对象转为BsonDocument后应用更新,再转回原类型,支持所有MongoDB更新操作符:
// 将内存对象转为BsonDocument var employeeBson = employee.ToBsonDocument(); // 渲染更新定义为可执行的BsonDocument var updateBson = def.Render(serializer, registry); // 应用更新到BsonDocument employeeBson.ApplyUpdate(updateBson); // 将更新后的BsonDocument转回Employee对象 employee = employeeBson.ToObject<Employee>();
方法二:反射手动解析(适合简单场景)
若仅需处理$set操作,可通过反射遍历更新字段并设置对象属性:
// 提取更新定义中的$set部分 var setUpdate = updateBson["$set"].AsBsonDocument; foreach (var element in setUpdate) { // 获取对象对应的属性 var property = typeof(Employee).GetProperty(element.Name); if (property != null) { // 将Bson值转换为属性类型并赋值 var value = element.Value.ToType(property.PropertyType); property.SetValue(employee, value); } }
完整可运行示例
using MongoDB.Bson; using MongoDB.Bson.Serialization; using MongoDB.Driver; using System.Reflection; class Program { class Employee { public string LastName { get; set; } = string.Empty; public string FirstName { get; set; } = string.Empty; } public static void Main(string[] args) { Employee employee = new Employee() { LastName = "ln", FirstName = "test" }; var def = Builders<Employee>.Update.Set("LastName", "ln1"); def = def.Set("FirstName", "another"); var registry = BsonSerializer.SerializerRegistry; var serializer = registry.GetSerializer<Employee>(); var updateBson = def.Render(serializer, registry); // 方法一测试 var employeeBson = employee.ToBsonDocument(); employeeBson.ApplyUpdate(updateBson); employee = employeeBson.ToObject<Employee>(); Console.WriteLine($"方法一结果:LastName={employee.LastName}, FirstName={employee.FirstName}"); // 重置对象测试方法二 employee = new Employee() { LastName = "ln", FirstName = "test" }; var setUpdate = updateBson["$set"].AsBsonDocument; foreach (var element in setUpdate) { var property = typeof(Employee).GetProperty(element.Name); if (property != null) { var value = element.Value.ToType(property.PropertyType); property.SetValue(employee, value); } } Console.WriteLine($"方法二结果:LastName={employee.LastName}, FirstName={employee.FirstName}"); } }
注意事项
- 方法一兼容性更强,支持
$inc、$push等所有MongoDB更新操作符; - 方法二仅针对
$set操作,如需支持其他操作符,需自行扩展解析逻辑。
内容的提问来源于stack exchange,提问作者No Name
相关产品推荐
相关产品推荐

