简体   繁体   中英

Linq dynamic where count?

Is it possible to use list in where. I want somethink like this:

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

I want to filter customers with using checkboxes. If I select FirstName and Number then where clause will be generated

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

If I select only number then where clause will be generated

.where(x.Number == someNumber)

If I select FirstName, LastName and Number then where clause will be generated

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

I mean not only dynamic column names, also I want to generate where clauses count, too. Column names and values are came from list:

I hope, I can explain. Thanks in advance.

Use more then one step to generate the query:

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 you don't want to do the multiple if statements I can think of two other ways:

  • Build your own expression trees by hand:

Expression Trees (C# and Visual Basic) How to: Use Expression Trees to BUild Dynamic Queries (C# and Visual Basic)

The other method is to create a complex where clause that used ANDs and ORs to only filter if this column searc option is selected:

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

With this one, you want to be careful about the execution time, hook up SQL Profiler to see what is happening.

I still recommend the first option.

You could give Dynamic LINQ a try. With this you could write something like:

var db = new NorthwindDataContext;
var query = db.Products.Where("CategoryID=2 And UnitPrice>3").OrderBy("SupplierId");

I think the (first suggestion in the) answer above is good - I effectively do the same thing in my current architecture, but its wrapped up a bit more, fundamentally into 2 parts:

  1. I have a filter class (specific to any relevant entities... in your case, would probably be called "CustomerFilter") This class has a method that looks something like this (just an example)

     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. I have an extension method (as a helper, doesn't necessarily have to be an extension method) which essentially loops through all filters and builds the where from it. Code looks like this (more or less):

     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; } 

Then, the usage of it might look something like this:

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

So like I say, it amounts to the same thing as the previous answer (and I've simplified a lot of my code here for brevity), but I've found wrapping it up and abstracting it in this way to be very useful in applications where there are lots of filters, on lots of entities, and the specific filters to be applied are user driven.

I would avoid using strings because you would lose type safety. Instead I would use expression trees to build up the expression for your where clause.

        //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());

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM