【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.在对象创建时,就要将对象中的数组属性初始化,否则在更新时无法插入子项。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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里面查询,发现第一个子项仍然存在。

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

 

posted @   のんきネコ  阅读(913)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
历史上的今天:
2014-06-13 规避字符串在传递过程中造成的编码问题
点击右上角即可分享
微信分享提示