1

是否可以在 where 中使用列表。我想要这样的想法:

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

4 回答 4

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 语句,我可以想到另外两种方法:

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

表达式树(C# 和 Visual Basic) 如何:使用表达式树构建动态查询(C# 和 Visual Basic)

另一种方法是创建一个复杂的 where 子句,该子句使用 AND 和 OR 仅在选择此列搜索选项时进行过滤:

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

有了这个,你要小心执行时间,连接 SQL Profiler 看看发生了什么。

我仍然推荐第一个选项。

于 2012-12-14T14:59:53.333 回答
1

你可以试试动态 LINQ 。有了这个,您可以编写如下内容:

var db = new NorthwindDataContext;
var query = db.Products.Where("CategoryID=2 And UnitPrice>3").OrderBy("SupplierId");
于 2012-12-14T15:55:12.183 回答
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;
    }
    

然后,它的用法可能如下所示:

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

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

于 2012-12-14T20:19:39.217 回答
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());
于 2012-12-14T21:24:56.703 回答