在实际更新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. Android Gradle 完整指南(转)

    本文转载来自:http://www.jianshu.com/p/9df3c3b6067a 为什么需要学Gradle? Gradle 是 Android 现在主流的编译工具,虽然在Gradle 出现之前 ...

  2. getline数据来源你的三种方式

    (1)getline从交互式的用户输入中\c中获取内容: # awk 'BEGIN {system("echo \"Input your name:\"");g ...

  3. 使用最快速的方式激活windows10专业版

    1.安装win10专业版 2.在桌面新建“文本文档.txt” 3.复制如下代码到新新建的“文本文档.txt”中 slmgr /ipk VK7JG-NPHTM-C97JM-9MPGT-3V66T slm ...

  4. Alpha阶段第八次Scrum Meeting

    情况简述 Alpha阶段第八次Scrum Meeting 敏捷开发起始时间 2016/10/31 00:00 敏捷开发终止时间 2016/10/32 00:00 会议基本内容摘要 跟助教进行了交流,明 ...

  5. 狼人杀BETA阶段计划简介

    狼人杀beta阶段任务与目标 简介 一.前言 狼人杀alpha阶段终于在组团刷夜中结束了,我们取得了一些成绩,同时也暴露了团队的一些问题.但不管怎样,有了在alpha版本中收获的经验,我们将在beta ...

  6. 11月10日上午ajax基础知识、用ajax做登录页面、用ajax验证用户名是否可用、ajax动态调用数据库

    1.ajax的基础知识 ajax是结合了jquery.php等几种技术延伸出来的综合运用的技术,不是新的内容.ajax也是写在<script>标签里面的. 如果使用ajax一定是要有1个处 ...

  7. webpack解惑:require的五种用法 (转)

    我之前在 <前端搭环境之从入门到放弃>这篇文章中吐槽过,webpack中可以写commonjs格式的require同步语法,可以写AMD格式的require回调语法,还有一个require ...

  8. HBase中批量修改

    先随便写写..做个随笔记录 使用Rest连接操作Hbase.. 是微软提供的  Microsoft.Hbase.Client 类库.. 版本是0.4.1.0 一直知道   client.StoreCe ...

  9. IOS热更新-JSPatch实现原理+Patch现场恢复

    关于HotfixPatch 在IOS开发领域,由于Apple严格的审核标准和低效率,IOS应用的发版速度极慢,稍微大型的app发版基本上都在一个月以上,所以代码热更新(HotfixPatch)对于IO ...

  10. C语言基础(3)-二进制、八进制、十六进制

    1.二进制 一个位只能表示0或者1两种状态,简称bit(比特) 一个字节为8个二进制数,称为8位,简称BYTE(字节) 一个字为2个字节,简称WORD. 两个字为双字,简称DWORD,占32个bit ...