伯克动态在哪里数?

时间:2012-12-14 14:49:17

标签: c# linq where dynamic-linq

是否可以在哪里使用列表。我想要这样想:

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

我想使用复选框过滤客户。如果我选择FirstName和Number,那么将生成where子句

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

如果我只选择数字,那么将生成where子句

.where(x.Number == someNumber)

如果我选择FirstName,LastName和Number,那么将生成where子句

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

我的意思不仅是动态列名,我也想生成where子句的数量。列名和值来自列表:

我希望,我可以解释一下。提前谢谢。

4 个答案:

答案 0 :(得分:4)

使用多于一步来生成查询:

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语句,我可以考虑另外两种方式:

  • 手工构建自己的表达式树:

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

另一种方法是创建一个复杂的where子句,如果选择了这个列searc选项,则使用AND和OR来仅过滤:

.where(x =&gt;(IsFirstNameFilter == true&amp;&amp; x.FirstName = FirstNameData)||(IsLastNameFilter == true&amp;&amp; x.LastName = LastNameData)|| ...); < / p>

有了这个,你要小心执行时间,连接SQL事件探查器,看看发生了什么。

我仍然推荐第一个选项。

答案 1 :(得分:1)

您可以尝试Dynamic LINQ。有了这个,你可以写下这样的东西:

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

答案 2 :(得分:1)

我认为(上面的第一个建议)答案是好的 - 我在我目前的架构中有效地做了同样的事情,但它包含了更多,从根本上分为两部分:

  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;
    }
    
  3. 然后,它的用法可能如下所示:

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

    就像我说的那样,它与前面的答案相同(为了简洁起见,我在这里简化了很多代码),但我发现将它包装起来并以这种方式将其抽象为在许多实体上有大量过滤器的应用程序中非常有用,并且要应用的特定过滤器是用户驱动的。

答案 3 :(得分:1)

我会避免使用字符串,因为你会失去类型安全性。相反,我会使用表达式树来构建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());