在实际更新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. 【bzoj3505】 Cqoi2014—数三角形

    http://www.lydsy.com/JudgeOnline/problem.php?id=3505 (题目链接) 题意 给定一个n*m的网格,请计算三点都在格点上的三角形共有多少个. Solut ...

  2. mogodb3.2源码安装

    mogodb3.2源码安装 下载链接: http://www.mongodb.org/downloads 1.环境准备: 1.mkdir -p /data/tgz #创建存放软件的目录 2.mkdir ...

  3. php cli配置文件问题

    引言 今天在教别人使用protobuf的时候,无意中发现了一个php cli模式下的诡异问题,费了老半天的找到解决方法了,这里拿出来分享下. 问题描述 我们这边最先引入了protobuf协议,使用的是 ...

  4. 【CityHunter】通过Unity3D来制作游戏中AR部分的内容

    嗯,最近再考虑,CityHunter中,玩家攻略藏宝图时,为了增加可玩性,应该增强在AR部分的游戏性.最近特别火的游戏<Pokemon Go>在打开摄像头以后,可以看到小精灵,实际上,如果 ...

  5. PL/SQL 将旧表的一些字段赋值给新的表中的字段的做法

    INSERT INTO 新表(字段1,字段2,.......) SELECT 字段1,字段2,...... FROM 旧表

  6. entity1

  7. yii2 composer安装

    安装Yii2 1.安装composer 在命令行输入 curl-sS https://getcomposer.org/installer | php mv composer.phar /usr/loc ...

  8. windows安装mysql5.7

    1下载mysql http://dev.mysql.com/downloads/mysql/2解压后,新建一个data文件夹,复制my-default.ini,并改名为my.ini,添加下面内容[cl ...

  9. 2015.4.25-2015.5.1 字符串去重,比例圆设计,中奖机和canvas橡皮擦效果等

    1.字符串去重,html模板取值   2.javascript正则表达式之$1...$9   3.jquery插件   4.返回上一页并刷新 解决方法: <a href ="javas ...

  10. MySQL数据库索引的设计原则

    为了使索引的使用效率更高,在创建索引时,必须考虑在哪些字段上创建索引和创建什么类型的索引. 1.选择唯一性索引 唯一性索引的值是唯一的,可以更快速的通过该索引来确定某条记录.例如,学生表中学号是具有唯 ...