mongodb C#官方驱动2.2 update方法封装
C#官方驱动2.2的更新方式使用的是updatedefinition 的形式进行更新,因此想封装它的人太多了
写这篇文章之前,博客园确实也有不少update方法的封装,思路大概是通过反射对象属性构建来updatedefinition,如果有内部对象或者列表则继续递推构建,自己亲测发现几个问题
1. 字段decimal类型,在数据库中生成_t-_v形式保存,非常的不直观,在查询的时候直接报错——无法完成反序列化
2. string[]数组无法保存,方法有漏洞,虽然自己添加了一些判断,但是还会存在问题3
3. IList<T> 的保存问题,代码是遍历数组生成updatedefinition,但是却没有考虑到 如果数组有 3个变成2个的时候,只能更新到List[0]和List[1] 没有删除List[2]
到此我再也改不下去了,不知道还有什么坑,决定自己写一个update,思路是这样的
既然mongodb存储的是bson格式,那么可以将对象序列化为json或者bson格式进行存储,查看api发现通过bsondocument也是可以更新文档,那么假设成立,不过改需要包含legacy
的驱动,nuget对应的是mongocssharpdriver;
一开始发现api支持JSON可以转化为BsonDocument,写的是将Model进行JSON序列化,但是问题来了,它把BsonIgnore属性的字段也序列化了,从而导致查询出错,想到添加JsonIgnore属性,
程序员都知道这是万万不行的,提供api时假如有这个属性也会忽略,此法行不通
因此还得使用Bson序列化器,他可以轻松的解决BsonIgnore的问题,不管层级有多深该属性都起作用,兼容了mongodb驱动的问题而不影响其他功能。
快上班了,是上代码的时候了
internal Task<UpdateResult> Update<T>(T entity, string[] includeFields = null, string[] excludeFields = null) where T : BaseMongoEntity
{
string bson = string.Empty;
using (var sw = new StringWriter())
{
BsonWriter writer = new JsonWriter(sw);
BsonSerializer.Serialize(writer, entity);
bson = sw.GetStringBuilder().ToString();
writer.Close();
sw.Close();
}
BsonDocument bsonSetDoc = BsonSerializer.Deserialize<BsonDocument>(bson);
//排除Id 和 _t
bsonSetDoc.Remove("_id");
bsonSetDoc.Remove("_t");
//排除忽略的字段
if (excludeFields != null && excludeFields.Length > 0)
{
excludeFields.Distinct().ToList().ForEach(field => { bsonSetDoc.Remove(field); });
}
//需要更新的字段
if (includeFields != null && includeFields.Length > 0)
{
var allFields = bsonSetDoc.Select(m => m.Name).ToList();
allFields.Except(includeFields).ToList().ForEach(field => { bsonSetDoc.Remove(field); });
}
var filter = new BsonDocument().AddRange(new List<BsonElement>() { new BsonElement("_id", entity.Id) });
var update = new UpdateDocument("$set", bsonSetDoc);
return _client.Collection<T>().UpdateOneAsync(filter, update);
}
当然需要注意的是,如果你仅仅是更新一两个字段或者自增字段等,还是构建updatedefinition比较合适
浙公网安备 33010602011771号