回到目錄
遞歸遞歸我愛你!隻要你想做,就一定能成功!
從一到二,從二到三,它是容易的,也是沒什麼可搞的,或者說,它是一種流水線的方式,而從三到十,從十到百,它注定要有一個質的突破,否則,它會把你累死,代碼寫的讓你自己都覺得想吐!有時,我們是被逼出來的,對于一種功能的實作,我們有時需要有從三到十的态度中,就像0的出現是人類最大的突破之一……
回歸到執行個體,在MongoDB中實體可以嵌套,這在C#裡叫做複雜屬性,即類中也有類級的屬性,這在面向對象裡叫做“組合”(設計模式中的組合模式),它經常在日常開發環境中見到,大家都耳熟能詳了,呵呵,而在mongodb裡,如果希望對N層嵌套的類型進行update操作,這絕對不是一件容易的事,最起碼在大叔架構裡,在面向linq的文法裡,它并不容易,但經過大叔的努力,和對遞歸的依賴,把這個問題解決了!
這才有今天的文章:遞歸遞歸我愛你!
一 從超級變态的類開始
public class Person : Base
{
public Person()
{
Contact = new Test.Contact();
OrderList = new List<Order>();
}
public string Name { get; set; }
public DateTime LastContact { get; set; }
public DateTime Birthday { get; set; }
public int Age { get; set; }
#region 值對象
/// <summary>
/// 統計
/// </summary>
public Total Total { get; set; }
/// <summary>
/// 聯系方式和位址
/// </summary>
public Contact Contact { get; set; }
#endregion
#region 清單實體
public List<Order> OrderList { get; set; }
#endregion
}
public class Section
{
public string SectionID { get; set; }
public string SectionName { get; set; }
}
public class Area
{
public Area()
{
Section = new Section();
}
public string Province { get; set; }
public string City { get; set; }
public string District { get; set; }
public Section Section { get; set; }
}
public class Contact
{
public Contact()
{
Area = new Area();
}
public string PostCode { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public Area Area { get; set; }
}
public class Total
{
public int Count { get; set; }
public int Max { get; set; }
}
public class Order
{
public Order()
{
Id = MongoDB.Bson.ObjectId.GenerateNewId().ToString();
this.OrderDetail = new List<OrderDetail>();
this.User_Info = new User_Info();
}
public string UserId { get; set; }
public string UserName { get; set; }
public string Id { get; set; }
public double Price { get; set; }
public DateTime AddTime { get; set; }
public User_Info User_Info { get; set; }
public List<OrderDetail> OrderDetail { get; set; }
}
public class User_Info
{
public User_Info()
{
Id = MongoDB.Bson.ObjectId.GenerateNewId().ToString();
}
public string Id { get; set; }
public string Name { get; set; }
}
public class OrderDetail
{
public OrderDetail()
{
Id = MongoDB.Bson.ObjectId.GenerateNewId().ToString();
}
public string Id { get; set; }
public string OrderId { get; set; }
public string ProductName { get; set; }
public int Count { get; set; }
public double Price { get; set; }
public string SellerId { get; set; }
}
看到上面的類,絕對夠你喝一壺的,呵呵,這是一個複雜的類型People,它有實體屬性contact和清單屬性OrderList
而對于之前大叔的架構裡,這種結構是不被支援的,大叔隻能支援到3級嵌套,但這顯然是不夠的,最後大叔硬着頭皮沖了上來,把這個骨頭啃掉了,哈哈!
下面貢獻我的Recursion代碼
/// <summary>
/// 遞歸建構Update操作串
/// </summary>
/// <param name="fieldList"></param>
/// <param name="property"></param>
/// <param name="propertyValue"></param>
/// <param name="item"></param>
/// <param name="father"></param>
private void GenerateRecursion(
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);
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 != EntityKey)//更新集中不能有實體鍵_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<TEntity>> GeneratorMongoUpdate(TEntity item)
{
var fieldList = new List<UpdateDefinition<TEntity>>();
foreach (var property in typeof(TEntity).GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
GenerateRecursion(fieldList, property, property.GetValue(item), item, string.Empty);
}
return fieldList;
}
最後的結果,當然是在N層失敗之後,取得了成功,呵呵!
最後,送給大家一句,多看看資料結構和算法,對各位在程式開發領域,一定有非常大的幫助,最起碼在看問題的角度上,會有更多的,更合理的選擇!
作者:倉儲大叔,張占嶺,
榮譽:微軟MVP
QQ:853066980
支付寶掃一掃,為大叔打賞!
