在實際更新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 > 0){for (int index = 0; 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);elseGenerateRecursion(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);elseGenerateRecursion(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));elsefieldList.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里面查詢,發現第一個子項仍然存在。
? ?暫時還沒有好的解決方法,如果有涉及到數組子項的刪除操作,都是將整個對象刪掉,然后再重新插入,簡單粗暴。
?