【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里面查询,发现第一个子项仍然存在。

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

原文地址:https://www.cnblogs.com/nonkicat/p/5581726.html