MongoDB学习笔记~大叔框架实体更新支持N层嵌套~递归递归我爱你!

本文涉及的产品
云数据库 MongoDB,独享型 2核8GB
推荐场景:
构建全方位客户视图
简介:

递归递归我爱你!只要你想做,就一定能成功!

从一到二,从二到三,它是容易的,也是没什么可搞的,或者说,它是一种流水线的方式,而从三到十,从十到百,它注定要有一个质的突破,否则,它会把你累死,代码写的让你自己都觉得想吐!有时,我们是被逼出来的,对于一种功能的实现,我们有时需要有从三到十的态度中,就像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层失败之后,取得了成功,呵呵!

 

最后,送给大家一句,多看看数据结构和算法,对各位在程序开发领域,一定有非常大的帮助,最起码在看问题的角度上,会有更多的,更合理的选择!

本文转自博客园张占岭(仓储大叔)的博客,原文链接:MongoDB学习笔记~大叔框架实体更新支持N层嵌套~递归递归我爱你!,如需转载请自行联系原博主。

目录
相关文章
|
持续交付 jenkins Devops
WPF与DevOps的完美邂逅:从Jenkins配置到自动化部署,全流程解析持续集成与持续交付的最佳实践
【8月更文挑战第31天】WPF与DevOps的结合开启了软件生命周期管理的新篇章。通过Jenkins等CI/CD工具,实现从代码提交到自动构建、测试及部署的全流程自动化。本文详细介绍了如何配置Jenkins来管理WPF项目的构建任务,确保每次代码提交都能触发自动化流程,提升开发效率和代码质量。这一方法不仅简化了开发流程,还加强了团队协作,是WPF开发者拥抱DevOps文化的理想指南。
244 1
|
NoSQL BI 数据处理
【超实用攻略】MongoDB 聚合框架:从入门到精通,带你解锁数据处理新姿势!
【8月更文挑战第24天】MongoDB是一款以其灵活性和高性能闻名的NoSQL数据库。其强大的聚合框架采用管道式处理,允许用户定义多个数据处理阶段如过滤、分组等。本文通过示例数据库`orders`和`products`,演示如何利用聚合框架计算各产品的总销售额。示例代码展示了使用`$lookup`连接两集合、`$unwind`打平数组及`$group`按产品ID分组并计算总销售额的过程。这突显了聚合框架处理复杂查询的强大能力,是进行数据分析和报表生成的理想选择。
190 3
|
存储 NoSQL JavaScript
MongoDB存储过程实战:聚合框架、脚本、最佳实践,一文全掌握!
【8月更文挑战第24天】MongoDB是一款备受欢迎的文档型NoSQL数据库,以灵活的数据模型和强大功能著称。尽管其存储过程支持不如传统关系型数据库,本文深入探讨了MongoDB在此方面的最佳实践。包括利用聚合框架处理复杂业务逻辑、封装业务逻辑提高复用性、运用JavaScript脚本实现类似存储过程的功能以及考虑集成其他工具提升数据处理能力。通过示例代码展示如何创建订单处理集合并定义验证规则,虽未直接实现存储过程,但有效地演示了如何借助JavaScript脚本处理业务逻辑,为开发者提供更多实用指导。
232 2
|
存储 NoSQL 数据处理
【MongoDB大神级操作】揭秘聚合框架,让你的数据处理能力瞬间飙升,秒变数据界的超级英雄!
【8月更文挑战第24天】MongoDB是一款备受欢迎的非关系型数据库,以其灵活的文档模型和出色的可扩展性著称。其聚合框架尤其亮眼,能高效地对数据库中的数据执行复杂的转换与聚合操作,无需将数据导出到应用端处理,极大提升了数据处理的效率与灵活性。例如,在一个大型电商数据库中,聚合框架能轻松分析出最热卖的商品或特定时段内某类别商品的销售总额。通过一系列管道操作,如$unwind、$group等,可以对数据进行逐步处理并得到最终结果,同时还支持过滤、排序、分页等多种操作,极大地丰富了数据处理的能力,成为进行数据分析、报表生成及复杂业务逻辑实现的强大工具。
160 2
|
NoSQL Java 关系型数据库
MongoDB保姆级指南(下):无缝集成SpringData框架,一篇最全面的Java接入指南!
前面的两篇文章已经将MongoDB大多数知识进行了阐述,不过其中的所有内容,都基于原生的MongoDB语法在操作。可是,在实际的日常开发过程中,我们并不会直接去接触MongoDB,毕竟MongoDB只能算作是系统内的一个组件,无法仅依靠它来搭建出一整套系统。
655 1
|
持续交付 jenkins C#
“WPF与DevOps深度融合:从Jenkins配置到自动化部署全流程解析,助你实现持续集成与持续交付的无缝衔接”
【8月更文挑战第31天】本文详细介绍如何在Windows Presentation Foundation(WPF)项目中应用DevOps实践,实现自动化部署与持续集成。通过具体代码示例和步骤指导,介绍选择Jenkins作为CI/CD工具,结合Git进行源码管理,配置构建任务、触发器、环境、构建步骤、测试及部署等环节,显著提升开发效率和代码质量。
237 0
|
开发框架 NoSQL 关系型数据库
基于SqlSugar的开发框架循序渐进介绍(27)-- 基于MongoDB的数据库操作整合
基于SqlSugar的开发框架循序渐进介绍(27)-- 基于MongoDB的数据库操作整合
|
NoSQL 大数据 数据处理
MongoDB聚合框架与复杂查询优化:技术深度解析
【4月更文挑战第30天】本文深入探讨了MongoDB的聚合框架和复杂查询优化技术。聚合框架包含$match、$group、$sort和$project阶段,用于数据处理和分析,提供灵活性和高性能。优化查询涉及创建合适索引、使用聚合框架、简化查询语句、限制返回结果数、避免跨分片查询、只查询所需字段及使用$inc操作符。理解这些技术有助于提升MongoDB在大数据和复杂查询场景下的性能。
|
NoSQL 数据挖掘 BI
【MongoDB】MongoDB 聚合框架
【4月更文挑战第3天】【MongoDB】MongoDB 聚合框架
|
NoSQL MongoDB Docker
百度搜索:蓝易云【Scrapy框架之Docker安装MongoDB教程。】
现在,你已经成功在Scrapy框架中使用Docker安装并配置了MongoDB。你可以在Scrapy爬虫中使用MongoDB进行数据存储和处理。
297 0

推荐镜像

更多