zoukankan      html  css  js  c++  java
  • 【MongoDB】递归获取字段更新表达式,更新复杂数据类型对象

    在实际更新Mongo对象时发现,原有的更新代码无法更新复杂的数据类型对象。恰好看到张占岭老师有对该方法做相关的改进,因此全抄了下来。

    总的核心思想就是运用反射递归,对对象属性一层一层挖掘下去,循环创建父类及之类的更新表达式。

    相关代码如下:

    #region 递归获取字段更新表达式
    
    private List<UpdateDefinition<T>> GetUpdateDefinitions<T>(T entity)
    {
        var type = typeof(T);
        var fieldList = new List<UpdateDefinition<T>>();
    
        foreach (var property in type.GetProperties(BindingFlags.Instance | BindingFlags.Public))
        {
            GenerateRecursion<T>(fieldList, property, property.GetValue(entity), entity, "");
        }
    
        return fieldList;
    }
    
    private void GenerateRecursion<TEntity>(
          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 != "_id")//更新集中不能有实体键_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<T>> GeneratorMongoUpdate<T>(T item)
    {
        var fieldList = new List<UpdateDefinition<T>>();
        foreach (var property in typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public))
        {
            GenerateRecursion<T>(fieldList, property, property.GetValue(item), item, string.Empty);
        }
        return fieldList;
    }
    
    #endregion
    View Code

    在实际应用过程中,有几点要注意一下:

    1.在对象创建时,就要将对象中的数组属性初始化,否则在更新时无法插入子项。

    public class Users : MongoObj
    {
        public Users() 
        {
            Subs = new List<Sub>();
            Spell = new List<int>();
        }
    
        public string ObjectId_id { get; set; }
        public string Name { get; set; }
        public string Sex { set; get; }
        public List<int> Spell { get; set; }
        public List<Sub> Subs { get; set; }
    }   
    

    2.如果数组是一个复杂对象数据,那么要给对象添加一个_id,并且在对象初始化时就给_id赋值。

    public class Sub 
    {
        public Sub() 
        {
            _id = MongoDB.Bson.ObjectId.GenerateNewId().ToString();
        }
        public string _id { get; set; }
        public string aa {get;set;}
        public string bb{get;set;}
    }

    3.实际使用的时候发现无法对数组的子项做删除
       比如删除Subs中的第一个子项后,再到mongo里面查询,发现第一个子项仍然存在。

       暂时还没有好的解决方法,如果有涉及到数组子项的删除操作,都是将整个对象删掉,然后再重新插入,简单粗暴。

  • 相关阅读:
    绑定方式开始服务&调用服务的方法
    采用服务窃听电话示例
    后台服务运行示例
    Android短信监听器——示例
    利用广播实现ip拨号——示例
    Android图片的合成示例
    IIS 7.5 发布Web 网站步骤
    C# 中 多线程同步退出方案 CancellationTokenSource
    UML 类图常用表示方法.
    Socket Receive 避免 Blocking
  • 原文地址:https://www.cnblogs.com/nonkicat/p/5581726.html
Copyright © 2011-2022 走看看