-
C#教程之记一次Mongodb数据库更新操作之更新为数组或者对象
本站最新发布 C#从入门到精通
试听地址 https://www.xin3721.com/eschool/CSharpxin3721/
试听地址 https://www.xin3721.com/eschool/CSharpxin3721/
一直以来都是更新为一些简单的基础类型,直到有一天写了一个覆盖某一个字段(这个字段为数组)的更新操作。出问题了,数据库中出现了_t,_v……有点懵了。当然如果我们更新的时候设置类型是不会出现这个问题的,出现这种问题的一个前提是我们将数组赋值给了object类型的变量;由于时间关系问了一下同事,她给出了解决办法:mongodb的驱动去反序列化一下。问题就这么解决了,今天有时间记录一下,在写示例代码的时候发现更新对象也不行。
先看一下我们的数据,以及更新之后的截图:
示例数据
为什么会出现上图中的问题,打印了一下UpdateDefinition生成的shell命令,你会发现是这样的,
后面直接用同事的方法试了一下,再查看生成的语句就没问题了
既然UpdateDefinition可以转成字符串,并且他同样可以直接赋值为字符串,例如:UpdateDefinition<BsonDocument> updateDefinition = ""; ,那么我想了一下我们直接拼这个字符串应该就没问题了,当然这种我没有测试啊!
这里面还会遇到一个问题就是怎么判断一个object的真实类型,这里仅仅需要知道他是不是对象或者数组(这里是泛指所有的)。可能真的有点菜,不知道如果判断。看了一下官方文档:Type类,也没有找到,最后还是使用比较笨的方法:先序列化为字符串之后在反序列化为object,他会告诉你类型的。最后一个问题是这个解决问题的办法是不是最优的,感觉有点浪费……如果有哪位大神知道高效的方式,请不吝赐教,再次感谢。
最后看一下我的示例代码:
using MongoDB.Bson; using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Attributes; using MongoDB.Driver; using System; using System.Collections.Generic; using System.Linq; using System.Text.Encodings.Web; using System.Text.Json; namespace DDZ.MongodbUpdateArrayTest { class Program { static void Main(string[] args) { //清空表(新增之前先清空)、批量添加(初始化一些数据)、查询操作 //DeleteManyBatchAddFind(); //更新数据和Object测试 //UpdateArrayOrObject(); #region 寻找解决办法 var _client = new MongoClient("mongodb://localhost:27017"); var _database = _client.GetDatabase("FormBuilder"); var _collection = _database.GetCollection<BsonDocument>("UpdateArrayTest"); DateTime dtNow2 = DateTime.Now; List<KeyValueModel> keyValueModels = new List<KeyValueModel>() { new KeyValueModel(){ Key="Name",Value ="ddz001+++" }, new KeyValueModel(){ Key="Age",Value = 11 }, new KeyValueModel(){ Key="Valid",Value = false }, new KeyValueModel(){ Key="LastUpdatedTime",Value=dtNow2 }, new KeyValueModel(){ Key="Details",Value = new OtherInfoModel(){ Height=179.5f,Weight=80.5f,Married=false } }, new KeyValueModel() { Key="Bookmarks",Value = new List<BookmarkModel>() { new BookmarkModel() { Title="Yandex",Url="https://yandex.com/" }, new BookmarkModel() { Title="秘迹搜索",Url="https://mijisou.com/" } } } }; var tempUpdateObj = new { Name = "ddz001+++", Age = 11, Valid = false, LastUpdatedTime = dtNow2, Details = new OtherInfoModel() { Height = 179.5f, Weight = 80.5f, Married = false }, Bookmarks = new List<BookmarkModel>() { new BookmarkModel() { Title="Yandex",Url="https://yandex.com/" }, new BookmarkModel() { Title="秘迹搜索",Url="https://mijisou.com/" } } }; var tempUpdateDic = new Dictionary<string, object>() { { "Name", "ddz001+++"}, { "Age", ""}, { "Valid", false}, { "LastUpdatedTime", dtNow2}, { "Details", new OtherInfoModel() { Height = 179.5f, Weight = 80.5f, Married = false }}, { "Bookmarks", new List<BookmarkModel>() { new BookmarkModel() { Title="Yandex",Url="https://yandex.com/" }, new BookmarkModel() { Title="秘迹搜索",Url="https://mijisou.com/" } } }, }; if (keyValueModels.Any()) { var updateDefinitions = new List<UpdateDefinition<BsonDocument>>(); foreach (var item in keyValueModels) { if (item.Value == null) { updateDefinitions.Add(Builders<BsonDocument>.Update.Set(item.Key, BsonNull.Value)); continue; } string tempValueForStr = JsonSerializer.Serialize(item.Value); var tempValueForObj = JsonSerializer.Deserialize<object>(tempValueForStr); var tempValueType = ((JsonElement)tempValueForObj).ValueKind; switch (tempValueType) { case JsonValueKind.Object: case JsonValueKind.Array: { updateDefinitions.Add(Builders<BsonDocument>.Update.Set(item.Key, BsonSerializer.Deserialize<object>(tempValueForStr))); break; } default: { updateDefinitions.Add(Builders<BsonDocument>.Update.Set(item.Key, item.Value)); break; } } } var updateDefinition = Builders<BsonDocument>.Update.Combine(updateDefinitions); string tempUpdateStr = GetJsonStingByUpdateDefinition(updateDefinition); //var modifiedCount1 = _collection.UpdateMany(Builders<BsonDocument>.Filter.Eq("_id", "1"), updateDefinition).ModifiedCount; string tempUpdateStrFromObj = "{ \"$set\" : " + tempUpdateObj.ToJson() + " }"; //你会发现这个字符串中也是包含_t和_v,因为字典的值类型为object //驱动可能也是这么调用的,当然我没看源码 string tempUpdateStrFromDictionary = "{ \"$set\" : " + tempUpdateDic.ToJson() + " }"; //var modifiedCount2 = _collection.UpdateMany(Builders<BsonDocument>.Filter.Eq("_id", "1"), tempUpdateStrFromObj).ModifiedCount; } #endregion Console.WriteLine("Hello World!"); } /// <summary> /// 清空表(新增之前先清空)、批量添加(初始化一些数据)、查询操作 /// </summary> static void DeleteManyBatchAddFind() { var _client = new MongoClient("mongodb://localhost:27017"); var _database = _client.GetDatabase("FormBuilder"); var _collection = _database.GetCollection<UpdateArrayTestModel>("UpdateArrayTest"); // 如果表不存在不报错 var delCount = _collection.DeleteMany(Builders<UpdateArrayTestModel>.Filter.Empty).DeletedCount; var dtNow = DateTime.Now; List<UpdateArrayTestModel> initUpdateArrayTestModels = new List<UpdateArrayTestModel>() { new UpdateArrayTestModel() { Id="1",Name="ddz001",Age=10,Valid=true,CreateDate=dtNow,LastUpdatedTime=dtNow, Details=new OtherInfoModel(){ Height=169.5f, Weight=70.5f, Married=true }, Bookmarks=new List<BookmarkModel>() { new BookmarkModel(){ Title="百度一下",Url="https://www.baidu.com/" }, new BookmarkModel(){ Title="必应",Url="https://cn.bing.com/" } } }, new UpdateArrayTestModel() { Id="2",Name="ddz002",Age=20,Valid=true,CreateDate=dtNow,LastUpdatedTime=dtNow, Details=new OtherInfoModel(){ Height=170.5f, Weight=71.5f, Married=true }, Bookmarks=new List<BookmarkModel>() { new BookmarkModel(){ Title="搜狗搜索",Url="https://www.baidu.com/" }, new BookmarkModel(){ Title="多吉搜索",Url="https://www.dogedoge.com/" } } } }; _collection.InsertMany(initUpdateArrayTestModels); //这里的中文还没有问题 var queryResult = _collection.Find(Builders<UpdateArrayTestModel>.Filter.Empty).ToList(); //这里的中文就变成了unicode,你可以试一试序列化选项 var queryResultStr = JsonSerializer.Serialize(queryResult); JsonSerializerOptions jsonSerializerOptions = new JsonSerializerOptions{ Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping }; var queryResultStr2 = JsonSerializer.Serialize(queryResult, jsonSerializerOptions); } /// <summary> /// 更新数据和Object测试 /// </summary> static void UpdateArrayOrObject() { // 这里也遇到了同样的问题 // 1、https://jira.mongodb.org/browse/CSHARP-1984 // 其他相关 // 1、https://www.codeproject.com/Tips/1268019/MongoDB-Csharp-How-to-Deserialize-a-JSON-Containin // 2、https://blog.csdn.net/mzl87/article/details/85488319 var _client = new MongoClient("mongodb://localhost:27017"); var _database = _client.GetDatabase("FormBuilder"); var _collection = _database.GetCollection<BsonDocument>("UpdateArrayTest"); List<KeyValueModel> keyValueModels = new List<KeyValueModel>() { new KeyValueModel(){ Key="Name",Value ="ddz001+++" }, new KeyValueModel(){ Key="Age",Value = 11 }, new KeyValueModel(){ Key="Valid",Value = false }, new KeyValueModel(){ Key="LastUpdatedTime",Value=DateTime.Now }, new KeyValueModel(){ Key="Details",Value= new OtherInfoModel(){ Height=179.5f,Weight=80.5f,Married=false } }, new KeyValueModel() { Key="Bookmarks",Value = new List<BookmarkModel>() { new BookmarkModel() { Title="Yandex",Url="https://yandex.com/" }, new BookmarkModel() { Title="秘迹搜索",Url="https://mijisou.com/" } } } }; if (keyValueModels.Any()) { var updateDefinitions = new List<UpdateDefinition<BsonDocument>>(); foreach (var item in keyValueModels) { updateDefinitions.Add(Builders<BsonDocument>.Update.Set(item.Key, item.Value)); } var updateDefinition = Builders<BsonDocument>.Update.Combine(updateDefinitions); string tempUpdateStr = GetJsonStingByUpdateDefinition(updateDefinition); //var modifiedCount = _collection.UpdateMany(Builders<BsonDocument>.Filter.Eq("_id", "1"), updateDefinition).ModifiedCount; } } /// <summary> /// 将UpdateDefinition转为shell字符串 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="updateDefinition"></param> /// <returns></returns> static string GetJsonStingByUpdateDefinition<T>(UpdateDefinition<T> updateDefinition) { // 参考网址: // https://qa.1r1g.com/sf/ask/2243338471/ if (updateDefinition == null) return null; //updateDefinition.Render(_collection.DocumentSerializer,_collection.Settings.SerializerRegistry).ToString() return updateDefinition.Render(BsonSerializer.SerializerRegistry.GetSerializer<T>(), BsonSerializer.SerializerRegistry).ToString(); } } public class UpdateArrayTestModel { private string _id { get; set; } /// <summary> /// 主键ID /// </summary> public string Id { set => this._id = value; get => _id; } /// <summary> /// 姓名 /// </summary> public string Name { get; set; } /// <summary> /// 年龄 /// </summary> public int Age { get; set; } /// <summary> /// 是否有效 /// </summary> public bool Valid { get; set; } = true; /// <summary> /// 创建时间 /// </summary> [BsonDateTimeOptions(Kind = DateTimeKind.Unspecified)] public DateTime CreateDate { get; set; } /// <summary> /// 最后一次更新时间 /// </summary> [BsonDateTimeOptions(Kind = DateTimeKind.Unspecified)] public DateTime LastUpdatedTime { get; set; } /// <summary> /// 其他详细信息 /// </summary> public OtherInfoModel Details { get; set; } /// <summary> /// 我的书签 /// </summary> public IEnumerable<BookmarkModel> Bookmarks { get; set; } } public class OtherInfoModel { public float Height { get; set; } public float Weight { get; set; } public bool Married { get; set; } = true; } public class BookmarkModel { public string Title { get; set; } public string Url { get; set; } } public class KeyValueModel { public string Key { get; set; } public object Value { get; set; } } }
栏目列表
最新更新
C# 面向对象
假设客车的座位数是9行4列,使用二维数
C#基于接口设计三层架构Unity篇
C#线程 入门
C#读取静态类常量属性和值
C# 插件式编程
C# 委托与事件有啥区别?
C#队列学习笔记:队列(Queue)和堆栈(Stack
linq 多表分组左连接查询查询统计
C#队列学习笔记:MSMQ入门一
C# 在Word中添加Latex 数学公式和符号
inncheck命令 – 检查语法
基于UDP的服务器端和客户端
再谈UDP和TCP
在socket编程中使用域名
网络数据传输时的大小端问题
socket编程实现文件传输功能
如何优雅地断开TCP连接?
图解TCP四次握手断开连接
详细分析TCP数据的传输过程
SqlServer 利用游标批量更新数据
BOS只读状态修改
SQL Server等待事件—PAGEIOLATCH_EX
数据库多行转换为单一列
获取数据表最后最后访问,修改,更新,
计算经历的时间
SQL查询结果自定义排序
修改数据库默认位置
日期简单加或减
从日期获取年,月或日