MongoDB学习笔记~大叔框架实体更新支持N层嵌套~递归递归我爱你!
递归递归我爱你!只要你想做,就一定能成功!
从一到二,从二到三,它是容易的,也是没什么可搞的,或者说,它是一种流水线的方式,而从三到十,从十到百,它注定要有一个质的突破,否则,它会把你累死,代码写的让你自己都觉得想吐!有时,我们是被逼出来的,对于一种功能的实现,我们有时需要有从三到十的态度中,就像0的出现是人类最大的突破之一……
回归到实例,在MongoDB中实体可以嵌套,这在C#里叫做复杂属性,即类中也有类级的属性,这在面向对象里叫做“组合”(设计模式中的组合模式),它经常在日常开发环境中见到,大家都耳熟能详了,呵呵,而在mongodb里,如果希望对N层嵌套的类型进行update操作,这绝对不是一件容易的事,最起码在大叔框架里,在面向linq的语法里,它并不容易,但经过大叔的努力,和对递归的依赖,把这个问题解决了!
这才有今天的文章:递归递归我爱你!
一 从超级变态的类开始
public class Person : Base { public Person() { Contact = new Test.Contact(); OrderList = new List<Order>(); } public string Name { get; set; } public DateTime LastContact { get; set; } public DateTime Birthday { get; set; } public int Age { get; set; } #region 值对象 /// <summary> /// 统计 /// </summary> public Total Total { get; set; } /// <summary> /// 联系方式和地址 /// </summary> public Contact Contact { get; set; } #endregion #region 列表实体 public List<Order> OrderList { get; set; } #endregion } public class Section { public string SectionID { get; set; } public string SectionName { get; set; } } public class Area { public Area() { Section = new Section(); } public string Province { get; set; } public string City { get; set; } public string District { get; set; } public Section Section { get; set; } } public class Contact { public Contact() { Area = new Area(); } public string PostCode { get; set; } public string Email { get; set; } public string Phone { get; set; } public Area Area { get; set; } } public class Total { public int Count { get; set; } public int Max { get; set; } } public class Order { public Order() { Id = MongoDB.Bson.ObjectId.GenerateNewId().ToString(); this.OrderDetail = new List<OrderDetail>(); this.User_Info = new User_Info(); } public string UserId { get; set; } public string UserName { get; set; } public string Id { get; set; } public double Price { get; set; } public DateTime AddTime { get; set; } public User_Info User_Info { get; set; } public List<OrderDetail> OrderDetail { get; set; } } public class User_Info { public User_Info() { Id = MongoDB.Bson.ObjectId.GenerateNewId().ToString(); } public string Id { get; set; } public string Name { get; set; } } public class OrderDetail { public OrderDetail() { Id = MongoDB.Bson.ObjectId.GenerateNewId().ToString(); } public string Id { get; set; } public string OrderId { get; set; } public string ProductName { get; set; } public int Count { get; set; } public double Price { get; set; } public string SellerId { get; set; } }
看到上面的类,绝对够你喝一壶的,呵呵,这是一个复杂的类型People,它有实体属性contact和列表属性OrderList
而对于之前大叔的框架里,这种结构是不被支持的,大叔只能支持到3级嵌套,但这显然是不够的,最后大叔硬着头皮冲了上来,把这个骨头啃掉了,哈哈!
下面贡献我的Recursion代码
/// <summary> /// 递归构建Update操作串 /// </summary> /// <param name="fieldList"></param> /// <param name="property"></param> /// <param name="propertyValue"></param> /// <param name="item"></param> /// <param name="father"></param> private void GenerateRecursion( List<UpdateDefinition<TEntity>> fieldList, PropertyInfo property, object propertyValue, TEntity item, string father) { //复杂类型 if (property.PropertyType.IsClass && property.PropertyType != typeof(string) && propertyValue != null) { //集合 if (typeof(IList).IsAssignableFrom(propertyValue.GetType())) { foreach (var sub in property.PropertyType.GetProperties(BindingFlags.Instance | BindingFlags.Public)) { if (sub.PropertyType.IsClass && sub.PropertyType != typeof(string)) { var arr = propertyValue as IList; if (arr != null && arr.Count > 0) { for (int index = 0; index < arr.Count; index++) { foreach (var subInner in sub.PropertyType.GetProperties(BindingFlags.Instance | BindingFlags.Public)) { if (string.IsNullOrWhiteSpace(father)) GenerateRecursion(fieldList, subInner, subInner.GetValue(arr[index]), item, property.Name + "." + index); else GenerateRecursion(fieldList, subInner, subInner.GetValue(arr[index]), item, father + "." + property.Name + "." + index); } } } } } } //实体 else { foreach (var sub in property.PropertyType.GetProperties(BindingFlags.Instance | BindingFlags.Public)) { if (string.IsNullOrWhiteSpace(father)) GenerateRecursion(fieldList, sub, sub.GetValue(propertyValue), item, property.Name); else GenerateRecursion(fieldList, sub, sub.GetValue(propertyValue), item, father + "." + property.Name); } } } //简单类型 else { if (property.Name != EntityKey)//更新集中不能有实体键_id { if (string.IsNullOrWhiteSpace(father)) fieldList.Add(Builders<TEntity>.Update.Set(property.Name, propertyValue)); else fieldList.Add(Builders<TEntity>.Update.Set(father + "." + property.Name, propertyValue)); } } } /// <summary> /// 构建Mongo的更新表达式 /// </summary> /// <param name="entity"></param> /// <returns></returns> private List<UpdateDefinition<TEntity>> GeneratorMongoUpdate(TEntity item) { var fieldList = new List<UpdateDefinition<TEntity>>(); foreach (var property in typeof(TEntity).GetProperties(BindingFlags.Instance | BindingFlags.Public)) { GenerateRecursion(fieldList, property, property.GetValue(item), item, string.Empty); } return fieldList; }
最后的结果,当然是在N层失败之后,取得了成功,呵呵!
最后,送给大家一句,多看看数据结构和算法,对各位在程序开发领域,一定有非常大的帮助,最起码在看问题的角度上,会有更多的,更合理的选择!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示
2014-06-04 MVVM架构~knockoutjs系列之一些异常的总结(永久更新)
2014-06-04 Nginx系列~概念与windows下环境搭建
2012-06-04 架构,改善程序复用性的设计~第六讲 我的系统结构~将所有可以抽象的项目进行抽象(大结局)