Linq динамический, где считать?

Можно ли использовать список где. Я хочу что-то вроде этого:

public class Customer
{
    string FirtsName;
    string LastName;
    int Number;
    .....
}

Я хочу фильтровать клиентов с помощью флажков. Если я выберу Имя и Номер, то где будет сгенерировано предложение

.where(x=> x.FirstName == "SomeFirstName" && x.Number == someNumber)

Если я выберу только число, то где будет сгенерировано предложение

.where(x.Number == someNumber)

Если я выберу Имя, Фамилию и Номер, то где будет создано предложение

.where(x=> x.FirstName == "SomeFirstName" && x.Number == someNumber && x.LastName == "LastName")

Я имею в виду не только динамические имена столбцов, я также хочу сгенерировать, где учитываются предложения. Имена и значения столбцов взяты из списка:

Надеюсь, я могу объяснить. Заранее спасибо.


person AliRıza Adıyahşi    schedule 14.12.2012    source источник


Ответы (4)


Вы можете указать Динамический LINQ попробуйте. При этом вы можете написать что-то вроде:

var db = new NorthwindDataContext;
var query = db.Products.Where("CategoryID=2 And UnitPrice>3").OrderBy("SupplierId");
person Oliver    schedule 14.12.2012
comment
Я расширяю строку запроса, не так ли? Могу ли я динамически создавать строку предложения where? - person AliRıza Adıyahşi; 14.12.2012
comment
При этом вам нужно убедиться, что вы не вводите в свой код какие-либо возможности SQL Injection. Внедрение SQL — OWASP - person SBurris; 14.12.2012

Используйте более одного шага для создания запроса:

var query = originalList.AsQueryable();

if(/*Filtering on First Name*/)
{
  query = query.where(x => x.FirstName == FirstNameSearchString);
}

if(/*Filtering on Last Name */)
{
  query = query.where(x => x.LastName == LastNameSearchString);
}

if(/*Filtering on Number*/)
{
  query = query.where(x => x.Number== NumberSearchString);
}

//..And so on

//Do stuff with query

Если вы не хотите делать несколько операторов if, я могу придумать два других способа:

  • Создайте свои собственные деревья выражений вручную:

Деревья выражений (C# и Visual Basic) Как использовать деревья выражений для создания динамических запросов (C# и Visual Basic)

Другой метод заключается в создании сложного предложения where, в котором используются операторы AND и OR для фильтрации только в том случае, если выбран этот параметр поиска столбца:

.where(x => (IsFirstNameFilter == true && x.FirstName = FirstNameData) || (IsLastNameFilter == true && x.LastName = LastNameData) || ...);

С этим вы хотите быть осторожным со временем выполнения, подключите SQL Profiler, чтобы увидеть, что происходит.

Я все же рекомендую первый вариант.

person SBurris    schedule 14.12.2012
comment
Есть ли какой-нибудь динамический способ. Я не хочу использовать if. Поскольку для фильтрации требуется более 10 столбцов, я должен использовать 10 операторов if. - person AliRıza Adıyahşi; 14.12.2012

Я думаю, что (первое предложение в) ответе выше хорошо - я фактически делаю то же самое в своей текущей архитектуре, но он немного больше, по сути, на 2 части:

  1. У меня есть класс фильтра (конкретный для любых соответствующих объектов... в вашем случае, вероятно, будет называться «CustomerFilter»). Этот класс имеет метод, который выглядит примерно так (просто пример)

    public class CustomerFilters
    {
        public IEnumerable<Expression<Func<Customer, bool>>> Filters()
        {
            if (/*check if should filter on FirstName here*/)
            {
                yield return cust => cust.FirstName == FirstNameSearchString;
            }
            if (/*check if should filter on Surname here*/)
            {
                yield return cust => cust.Surname == SurnameSearchString;
            }
        }
    }
    
  2. У меня есть метод расширения (как помощник, не обязательно должен быть методом расширения), который, по сути, перебирает все фильтры и строит из них. Код выглядит так (более или менее):

    public static IQueryable<T> Filter<T>(this IQueryable<T> collection, IEnumerable<Expression<Func<T, bool>>> filters)
    {
        var results = collection;
        foreach (var f in filters)
        {
            results = results.Where(f);
        }
        return results;
    }
    

Тогда его использование может выглядеть примерно так:

var query = db.Customers.Filter(myCustomerFilterClass.Filters());

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

person Kevin Versfeld    schedule 14.12.2012

Я бы не стал использовать строки, потому что вы потеряете безопасность типов. Вместо этого я бы использовал деревья выражений для создания выражения для вашего предложения where.

        //The variable name for the parameter expression must match in all others
        var parameter = Expression.Parameter(typeof(Customer),"c");

        Expression<Func<Customer,bool>> firstNameCheck = c => c.FirstName == FirstNameSearchString;            
        Expression<Func<Customer,bool>> lastNameCheck = c => c.LastName == LastNameSearchString;
        Expression<Func<Customer,bool>> numberCheck = c => c.Number.ToString() == NumberSearchString;

        //Default to a true expression
        Expression ongoingExpression = Expression.Constant(true);

        if (//Filter on first name)
        {
            ongoingExpression = Expression.AndAlso(ongoingExpression, Expression.Invoke(firstNameCheck, parameter));
        }

        if (//Filter on last name)
        {
            ongoingExpression = Expression.AndAlso(ongoingExpression, Expression.Invoke(lastNameCheck, parameter));
        }

        if (//Filter on number)
        {
            ongoingExpression = Expression.AndAlso(ongoingExpression, Expression.Invoke(numberCheck, parameter));
        }



        var lambda = Expression.Lambda<Func<Customer, bool>>(ongoingExpression, parameter);            

        query = query.Where(lambda.Compile());
person Joel Kravets    schedule 14.12.2012