У меня есть несколько шаблонов слов (может быть, тысячи). Каждый шаблон имеет поля слияния, которые будут заполнены из базы данных. Мне не нравится писать отдельный код для каждого шаблона, а затем создавать приложение и разворачивать его при каждом изменении шаблона или добавлении поля в шаблон!Создайте динамические запросы LINQ из строки - используйте Reflection?
Вместо этого я пытаюсь определить все поля слияния в отдельном XML-файле, и для каждого поля я хочу написать «запрос», который будет вызываться при необходимости. EX:
- mergefield1 будет вызывать запрос "Case.Parties.FirstOrDefault.NameEn"
- mergefield2 будет вызывать запрос "Case.CaseNumber"
- mergefield3 будет вызывать запрос «Case.Documents.FirstOrDefault.DocumentContent.DocumentType "
- 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».
Если я правильно вас понимаю, я бы рекомендовал вам использовать выражение для построения запроса linq. Эти вещи позволяют создавать запрос linq во время выполнения. https://msdn.microsoft.com/ru-ru/library/mt654263.aspx - вот пример – Egorikas
Спасибо, Егорикас. На самом деле выражение немного сложнее. И не уверен, что это также применимо к моей проблеме. Но, я буду иметь другой взгляд на выражения. – drill