Linq dynamic where count?

泄露秘密 提交于 2019-11-30 16:33:24

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

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.

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