在实际更新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 > )
{
for (int index = ; 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

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

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

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

【MongoDB】递归获取字段更新表达式,更新复杂数据类型对象的更多相关文章

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

    回到目录 递归递归我爱你!只要你想做,就一定能成功! 从一到二,从二到三,它是容易的,也是没什么可搞的,或者说,它是一种流水线的方式,而从三到十,从十到百,它注定要有一个质的突破,否则,它会把你累死, ...

  2. Entity Framework 通过Lambda表达式更新指定的字段

    本来需要EF来更新指定的字段,后来在园子里找到了代码 var StateEntry = ((IObjectContextAdapter)dbContext).ObjectContext.ObjectS ...

  3. 2.Node.js access_token的获取、存储及更新

    文章目录:         1.Node.js 接入微信公众平台开发         2.Node.js access_token的获取.存储及更新 一.写在前面的话   上一篇文章中,我们使用 No ...

  4. EF更新指定字段.或个更新整个实体

    EF更新指定字段.或个更新整个实体 更新整个实体: public bool Update(Company compay) { if (compay != null) { dbContext.Entry ...

  5. MongoDB中的字段类型Id

    众所周知,在向MongoDB的集合中添加一条记录时,系统会自动增加一个字段名为"_id",类型为ObjectId的字段,其值为24位字符串,可以使用此值作为记录的唯一标识. 项目中 ...

  6. 解决Android SDK Manager更新(一个更新Host的程序的原理实现和源码)

    <ignore_js_op>     同学遇到了更新Android SDK的问题,而且Goagent现在也无法用来更新.就想到了用替代Host的方法,添加可用的谷歌地址来实现更新.    ...

  7. 线段树&&线段树的创建线段树的查询&&单节点更新&&区间更新

    目录 线段树 什么是线段树? 线段树的创建 线段树的查询 单节点更新 区间更新 未完待续 线段树 实现问题:常用于求数组区间最小值 时间复杂度:(1).建树复杂度:nlogn.(2).线段树算法复杂度 ...

  8. kettle教程---kettle作业调度,根据更新时间增量更新

    本文接上一篇,只写到读取日志.在平时工作当中,会遇到这种情况,而且很常见.比如:增量抽取(每隔2个小时抽取截至到上次抽取时间的记录) 本文中会用到作业,先来熟悉下作业的概念 简单地说,一个转换就是一个 ...

  9. ubuntu 怎么更新?ubuntu更新命令及方法

    ubuntu 怎么更新?ubuntu更新命令及方法 安装Ubuntu系统后,第一件事就是更新系统源.由于系统安装的默认源地址在英国,作为Ubuntu的主源,国内连接速度非常慢,所以我们要将它换成就近的 ...

随机推荐

  1. 【转载】浅谈HTTP中Get与Post的区别

    [转载]http://www.cnblogs.com/hyddd/ Http定义了与服务器交互的不同方法,最基本的方法有4种,分别是GET,POST,PUT,DELETE.URL全称是资源描述符,我们 ...

  2. [webpack] webpack-dev-server介绍及配置

    webpack-dev-server是webpack官方提供的一个小型Express服务器.使用它可以为webpack打包生成的资源文件提供web服务.webpack-dev-server官方文档 w ...

  3. 关于GIL

    1同一时刻只有一个线程通过一个线程到解释器运行 2在多核上会有些不一样 不仅仅会降低python的效率 并且还会影响到整个机器系统的效率 python的gil是每100条cpu指令开始check 如果 ...

  4. 【USACO 2.4】Cow Tours (最短路)

    题意:给你n(最多150)个点的坐标,给出邻接矩阵,并且整个图至少两个联通块,现在让你连接一条边,使得所有可联通的两点的最短距离的最大值最小. 题解:先dfs染色,再用floyd跑出原图的直径O($n ...

  5. UIlabel的字体自适应属性

    有时候我们需要UIlabel根据字数多少来减小字体大小,使得UIlabel能够显示全所有的文字.你需要做的就是设置minimumScaleFactor.minimumScaleFactor默认值是0, ...

  6. Leetcode 255. Verify Preorder Sequence in Binary Search Tree

    验证一个list是不是一个BST的preorder traversal sequence. Given an array of numbers, verify whether it is the co ...

  7. 【Codeforces720D】Slalom 线段树 + 扫描线 (优化DP)

    D. Slalom time limit per test:2 seconds memory limit per test:256 megabytes input:standard input out ...

  8. Iptables防火墙NAT地址转换与端口转发

    开启系统转发功能: [root@localhost /]# vim /etc/sysctl.conf # Generated by iptables-save v1.4.7 on Thu May 12 ...

  9. 使用Spring进行统一日志管理 + 统一异常管理

    http://blog.csdn.net/king87130/article/details/8011843原文地址 统一日志异常实现类: 1 package com.pilelot.web.util ...

  10. [nosql之缓存memcache]安装篇LInux for Windows

    首先呢在PHP开发的过程中会用到很多缓存服务,从而提升访问质量或者临时存储一些数据. 优点 结构简单,读取速度快,易于维护.还有一些特性memcache redis mongodb都可以用来做为缓存用 ...