Linq dynamic where count?

纵饮孤独 提交于 2019-11-29 23:48:52

问题


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.


回答1:


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");



回答2:


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.




回答3:


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.




回答4:


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


来源:https://stackoverflow.com/questions/13880931/linq-dynamic-where-count

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!