在实际更新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. django static文件的引入方式

    1. 在django project中创建 static文件夹 2.settings.py中配置要在 STATIC_URL = '/static/'  下边 STATICFILES_DIRS = [ ...

  2. Asp.Net MVC<三> : ASP.NET MVC 基本原理及项目创建

    MVC之前的那点事儿系列 解读ASP.NET 5 & MVC6系列 MVC模拟(摘自ASP.NET MVC5框架揭秘) Asp.net中,通过HttpModule的形式定义拦截器,也就是路由表 ...

  3. NSUserDefaults:熟悉与陌生(转)

    转载自:http://swiftcafe.io/2016/04/04/nsuserdefaults/?hmsr=toutiao.io&utm_medium=toutiao.io&utm ...

  4. 解决Java接口内部类的main()方法无法打印输出的问题

    问题源自<Thinking in Java>关于内部类的章节,例子如下: public interface ClassInInterface{ void howdy(); public c ...

  5. bzoj 3262 陌上花开

    本质是一个三维偏序,一位排序后cdq分治,一维在子函数里排序,一维用树状数组维护. 把三维相等的合并到一个里面. #include<iostream> #include<cstdio ...

  6. signalr-源码

    1.一对一聊天 2.多对多 3.离线消息 1)群聊离线 2.1对一聊天离线 源码地址:https://github.com/aa1356889/SignalrCode 操作步骤 部署网站到iis 网上 ...

  7. Windows操作系统待整理

    12. 2001年10月25日Windows XP发布,Windows XP是基于Windows 2000代码的产品,同时拥有一个新的用户图形界面(叫做月神Luna),它包括了一些细微的修改.集成了防 ...

  8. 【转载】Arcengine效率探究之二——属性的更新

    文转载自hymyjl2010<Arcengine效率探究之二——属性的更新>   修改一批要素的属性有多种方法,当数据量较大时,若选择不当可能会大大影响速度. 一.IRowBuffer 方 ...

  9. [NHibernate]视图处理

    目录 写在前面 文档与系列文章 视图 一个例子 总结 写在前面 前面的文章主要讲了对物理数据表的操作,当然了Nhibernate同样可以操作视图,本文将讲nhibernate对视图操作的种种. 文档与 ...

  10. [Nhibernate]二级缓存(一)

    目录 写在前面 文档与系列文章 二级缓存 Nhibernate二级缓存提供程序 一个例子 总结 写在前面 上篇文章介绍了nhibernate中一级缓存的相关内容,一级缓存过期时间和ISession对象 ...