2016-11-29 141 views
0

我有一些單詞模板(可能是數千)。每個模板都具有將從數據庫填充的合併字段。我不喜歡爲每個模板編寫單獨的代碼,然後構建應用程序並在模板更改或模板上的字段添加時進行部署!從字符串構建動態LINQ查詢 - 使用反射?

相反,我試圖在一個單獨的xml文件中定義所有合併字段,並且爲每個字段我想寫入「查詢」,這將在需要時調用。 EX:

  1. mergefield1將調用查詢 「Case.Parties.FirstOrDefault.NameEn」
  2. mergefield2將調用查詢 「Case.CaseNumber」
  3. mergefield3將調用查詢「Case.Documents.FirstOrDefault.DocumentContent.DocumentType 「

因此,對於一個特定的模板,我掃描其合併域,併爲每個合併域我把它單曲‘查詢定義’,並使用的EntityFramework和LINQ該請求到數據庫。防爆。它適用於這些查詢:「TimeSlots.FirstOrDefault.StartDateTime」或 「Case.CaseNumber」

這將是一個引擎,它將生成word文檔並用xml中的合併字段填充它。此外,它將適用於任何新模板或新合併字段。

現在,我已經使用反射工作了一個版本。

public string GetColumnValueByObjectByName(Expression<Func<TEntity, bool>> filter = null, string objectName = "", string dllName = "", string objectID = "", string propertyName = "") 
    { 
     string objectDllName = objectName + ", " + dllName; 
     Type type = Type.GetType(objectDllName); 
     Guid oID = new Guid(objectID); 
     dynamic Entity = context.Set(type).Find(oID); // get Object by Type and ObjectID 

     string value = ""; //the value which will be filled with data from database 

     IEnumerable<string> linqMethods = typeof(System.Linq.Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public).Select(s => s.Name).ToList(); //get all linq methods and save them as list of strings 

     if (propertyName.Contains('.')) 
     { 
      string[] properies = propertyName.Split('.'); 
      dynamic object1 = Entity; 
      IEnumerable<dynamic> Child = new List<dynamic>(); 
      for (int i = 0; i < properies.Length; i++) 
      { 
       if (i < properies.Length - 1 && linqMethods.Contains(properies[i + 1])) 
       { 
        Child = type.GetProperty(properies[i]).GetValue(object1, null); 
       } 
       else if (linqMethods.Contains(properies[i])) 
       { 
        object1 = Child.Cast<object>().FirstOrDefault(); //for now works only with FirstOrDefault - Later it will be changed to work with ToList or other linq methods 
        type = object1.GetType(); 
       } 
       else 
       { 
        if (linqMethods.Contains(properies[i])) 
        { 
         object1 = type.GetProperty(properies[i + 1]).GetValue(object1, null); 
        } 
        else 
        { 
         object1 = type.GetProperty(properies[i]).GetValue(object1, null); 
        } 
        type = object1.GetType(); 
       } 
      } 

      value = object1.ToString(); //.StartDateTime.ToString(); 
     } 

     return value; 
    } 

我不知道這是否是最好的方法。有沒有人有更好的建議,或者有人已經做過這樣的事情?

縮短它:想法是從一個字符串,如:「Case.Parties.FirstOrDefault.NameEn」的數據庫進行通用linq查詢。

+0

如果我以正確的方式理解你,我會推薦你​​使用Expression來構建linq查詢。這些東西允許你在運行時創建linq請求。 https://msdn.microsoft.com/ru-ru/library/mt654263.aspx - 這裏是一個例子 – Egorikas

+0

謝謝Egorikas。其實Expression有點複雜。並不確定這是否也適用於我的問題。但是,我會再看看錶達式。 – drill

回答

0

你的方法非常好。我毫不懷疑它已經有效。

另一種方法是使用表達式樹,如@Egorikas所建議的。

免責聲明:我的項目Eval-Expression.NET

總之所有者,這個庫可以讓您評估在運行時幾乎所有的C#代碼(你到底想要做什麼)。

我建議你改用我的圖書館。爲了保持代碼:

  • 更可讀
  • 更容易支持
  • 添加一些靈活性

public string GetColumnValueByObjectByName(Expression<Func<TEntity, bool>> filter = null, string objectName = "", string dllName = "", string objectID = "", string propertyName = "") 
{ 
    string objectDllName = objectName + ", " + dllName; 
    Type type = Type.GetType(objectDllName); 
    Guid oID = new Guid(objectID); 
    object Entity = context.Set(type).Find(oID); // get Object by Type and ObjectID 

    var value = Eval.Execute("x." + propertyName, new { x = entity }); 
    return value.ToString(); 
} 

該庫還允許您使用與IQueryable的動態字符串

Wiki:LINQ-Dynamic