在实际更新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. linux命令总结

    vmstat: linux监控命令,可以展现服务器状态值. 一般vmstat工具的使用是通过两个数字参数来完成的,第一个是采样的时间间隔,单位是秒,第二参数是采样的次数 例:vmstat 3 2  ( ...

  2. 【POJ 1390】Blocks

    http://poj.org/problem?id=1390 黑书上的例题,感觉我这辈子是想不到这样的dp了QAQ \(f(i,j,k)\)表示将\(i\)到\(j\)合并,并且假设未来会有\(k\) ...

  3. Sphinx在windows上的安装使用

    Sphinx是一个基于SQL的全文检索引擎,可以结合MySQL,PostgreSQL做全文搜索, 它可以提供比数据库本身更专业的搜索功能,使得应用程序更容易实现专业化的全文检索. Sphinx特别为一 ...

  4. CSS3选择器:nth-of-type

    碰到了个选择器,:nth-of-type <!DOCTYPE html> <html> <head> <meta http-equiv="Conte ...

  5. Problems about trees

    Problems (1) 给一棵带边权的树,求遍历这棵树(每个节点至少经过一次)再回到起点的最短路程. 答案是显然的:边权之和的两倍. (2)给一棵带边权的树,求遍历这棵树(每个节点至少经过一次)的最 ...

  6. bzoj 2301: [HAOI2011]Problem b

    2301: [HAOI2011]Problem b Time Limit: 50 Sec Memory Limit: 256 MB Submit: 3757 Solved: 1671 [Submit] ...

  7. 将DataTable生成树json

    protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { ListMenu(); } } protected ...

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

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

  9. Base64原理

    一.Base64编码由来 为什么会有Base64编码呢?因为有些网络传送渠道并不支持所有的字节,例如传统的邮件只支持可见字符的传送,像ASCII码的控制字符就 不能通过邮件传送.这样用途就受到了很大的 ...

  10. Web编程基础--HTML、CSS、JavaScript 学习之课程作业“仿360极速浏览器新标签页”

    Web编程基础--HTML.CSS.JavaScript 学习之课程作业"仿360极速浏览器新标签页" 背景: 作为一个中专网站建设出身,之前总是做静态的HTML+CSS+DIV没 ...