2016-11-29 2 views
0

У меня есть несколько шаблонов слов (может быть, тысячи). Каждый шаблон имеет поля слияния, которые будут заполнены из базы данных. Мне не нравится писать отдельный код для каждого шаблона, а затем создавать приложение и разворачивать его при каждом изменении шаблона или добавлении поля в шаблон!Создайте динамические запросы LINQ из строки - используйте Reflection?

Вместо этого я пытаюсь определить все поля слияния в отдельном XML-файле, и для каждого поля я хочу написать «запрос», который будет вызываться при необходимости. EX:

  1. mergefield1 будет вызывать запрос "Case.Parties.FirstOrDefault.NameEn"
  2. mergefield2 будет вызывать запрос "Case.CaseNumber"
  3. mergefield3 будет вызывать запрос «Case.Documents.FirstOrDefault.DocumentContent.DocumentType "
  4. Etc,

Таким образом, для конкретного шаблона я просматриваю свои поля слияния, и для каждого поля слияния Я принимаю` s „определение запроса“ и сделать этот запрос в базу данных с помощью EntityFramework и LINQ. Ex. он работает для этих запросов: «TimeSlots.FirstOrDefault.StartDateTime» или «Case.CaseNumber»

Это будет движок, который будет генерировать текстовые документы и заполнять их полями слияния из 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; 
    } 

Я не уверен, что это лучший подход. Кто-нибудь имеет лучшее предложение, или, возможно, кто-то уже сделал что-то подобное?

Чтобы укоротить его: идея состоит в том, чтобы генерировать общие запросы linq к базе данных из строки, например: «Case.Parties.FirstOrDefault.NameEn».

+0

Если я правильно вас понимаю, я бы рекомендовал вам использовать выражение для построения запроса linq. Эти вещи позволяют создавать запрос linq во время выполнения. https://msdn.microsoft.com/ru-ru/library/mt654263.aspx - вот пример – Egorikas

+0

Спасибо, Егорикас. На самом деле выражение немного сложнее. И не уверен, что это также применимо к моей проблеме. Но, я буду иметь другой взгляд на выражения. – 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

Смежные вопросы