2016-11-29 91 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