Динамически генерировать запросы LINQ - PullRequest
33 голосов
/ 29 февраля 2012

У нас есть объект

public class SomeObject
{
   public Name {get;set;}
   public City {get;set;}
   public State {get;set}
   //various other parameters.  Let's say there's ~20
}

Можно ли динамически создавать новые запросы LINQ без перекомпиляции исходного кода? Вместо этого параметры запроса поступают из структуры XML, которая хранится и обновляется в базе данных.

var result = from i in someObj
             where 
             //XML requests Name = 'Bob'...so append this where clause
             name = 'Bob'

Можно ли это сделать?

Ответы [ 7 ]

115 голосов
/ 02 марта 2012

Вот решение с деревьями выражений:

var param = Expression.Parameter(typeof(SomeObject), "p");
var exp = Expression.Lambda<Func<SomeObject, bool>>(
    Expression.Equal(
        Expression.Property(param, "Name"),
        Expression.Constant("Bob")
    ),
    param
);
var query = someObj.Where(exp);

Я знаю, что это намного сложнее, но это может быть полезно в разы.

27 голосов
/ 29 февраля 2012

Вы наверняка захотите взглянуть на Dynamic Linq , который позволит вам определять условия запроса в виде текста.

Что касается динамического добавления условий, вы можете добавлять условия в запрос, используя синтаксис, аналогичный;

if(CategoryIsImportant)
    myQuery = myQuery.Where("CategoryId=2");

все, что вы можете (довольно легко) кодировать в формате XML по вашему выбору.

26 голосов
/ 29 февраля 2012

Мне сложно сказать, основываясь на вашем вопросе, но в некоторых случаях вам не нужен динамический Linq, и вы можете просто сделать это ...

var result = from o in someObj 
             where (Name == null || o.Name == Name)
             && (City == null || o.City == City)
             && (State == null || o.State == State)
             select o;

Это по существу не позволит данным бытьфильтруется, когда рассматриваемый параметр равен нулю.И это все еще хорошо работает благодаря короткому замыканию в C #.

9 голосов
/ 29 февраля 2012

Полагаю, вам придется копаться в Деревьях выражений . Я не очень углубился в это, поэтому не могу создать пример для вас, но я знаю, что вы можете использовать деревья выражений для динамического построения ваших запросов, а затем вызывать .Compile (в коде), чтобы он работал.

Собственно, вот лучшая ссылка Построение динамических запросов с деревьями выражений . Это должно дать вам именно то, что вы хотите, и довольно кратко, что это такое. Это должно послужить хорошим примером для вас:)

8 голосов
/ 29 февраля 2012

Может быть, вам поможет Dynamic Linq: Dynamic linq часть 1: Использование библиотеки динамических запросов linq

query = query.Where("Id = 123 And Age > 18");

Или вы можете напрямую управлять запросом Linq:

query = query.Where(x=>x.Id == 5);
5 голосов
/ 29 февраля 2012

Я предполагаю, что вы хотите ввести дополнительные фильтры, в зависимости от содержимого вашего XML.Чтобы продолжить пример с StriplingWarrior:

var name = GetNameFromXml();
var city = GetCityFromXml();
var state = GetStateFromXml();

var result = someObj;
if (name != null)
    result = result.Where(i => i.Name == name);
if (city != null)
    result = result.Where(i => i.City == city);
if (state != null)
    result = result.Where(i => i.State == state);

Таким образом, вы будете применять любое количество фильтров (от одного до всех трех) в зависимости от того, что на самом деле указано в вашем XML.

3 голосов
/ 29 февраля 2012

Да, на самом деле это довольно просто:

var name = GetBobNameFromXml();
var result = someObj.Where(i => i.Name == name);

Вы также можете выбрать, применять ли критерии по частям.

var result = someObj;
var name = xmlCriteria.Name;
if(!string.IsNullOrEmpty(name))
{
    result = result.Where(i => i.Name == name);
}
// follow the same pattern for city, state, etc.

Вы можете даже использовать шаблон, который использует словарь с именованным ключом для критериальных функций, чтобы избежать кучки if операторов.

foreach(var criterionPair in xmlCriteria)
{
    var value = criterionPair.Value;
    result = result.Where(i => propGetters[criterionPair.PropertyName](i, value));
}

По сути, вы можете многое сделать в этом направлении. Если вы хотите получить ответ, более конкретно соответствующий вашей ситуации, вам нужно будет предоставить более конкретный вопрос.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...