【问题标题】:Create WHERE condition with multiple columns使用多列创建 WHERE 条件
【发布时间】:2015-02-05 12:27:01
【问题描述】:

我有以下方法:

protected override List<Contractor> GetSearchResults()
{
    List<User> users = UnitOfWork.UserRepository.Get(
            user =>
            (!String.IsNullOrEmpty(FirstName) && user.FirstName.Contains(FirstName)) &&
            (!String.IsNullOrEmpty(LastName) && user.LastName.Contains(LastName)))
            .ToList();
    return users ;
}

这只是一个“简化”的例子。实际上,我的 where 条件还有一些“列”。

这两个“条件”都与一个与运算符 (&&) 相关联。这意味着:

  • 必须填写名字并且必须匹配AND
  • 第二个名字必须填写且必须匹配

这不是我想要的。使用或运算符 (||) 更改代码,例如

protected override List<Contractor> GetSearchResults()
{
    List<User> users = UnitOfWork.UserRepository.Get(
            user =>
            (!String.IsNullOrEmpty(FirstName) && user.FirstName.Contains(FirstName)) ||
            (!String.IsNullOrEmpty(LastName) && user.LastName.Contains(LastName)))
            .ToList();
    return users ;
}

没有提供想要的解决方案,因为:

  • 必须填写名字并且必须匹配或
  • 第二个名字必须填写并匹配

那么,我想要什么?

例如,如果我必须在我的数据库中跟踪记录:

  • 怀特,保罗
  • 米勒,约翰
  • 米勒,莉亚

我希望得到以下结果:

  • 如果只输入姓氏“Miller”,我想获得两个 记录。
  • 如果输入了姓氏和名字(“Miller”和“John”),我希望只获得一条记录。

我的条件不符合这些要求,我不知道如何“简单地”改变它们。

这样更合适吗:

protected override List<Contractor> GetSearchResults()
{
    List<User> users = UnitOfWork.UserRepository.Get(
            user =>
            (String.IsNullOrEmpty(FirstName) || (!String.IsNullOrEmpty(FirstName) && user.FirstName.Contains(FirstName))) &&
            (String.IsNullOrEmpty(LastName) || (!String.IsNullOrEmpty(LastName) && user.LastName.Contains(LastName))))
            .ToList();
    return users ;
}

这似乎有效。但是随着越来越多的列,它肯定看起来很难看并且难以阅读。有什么方法可以简化这个任务?

【问题讨论】:

  • 我相信(String.IsNullOrEmpty(FirstName) || (!String.IsNullOrEmpty(FirstName) &amp;&amp; user.FirstName.Contains(FirstName)))可以简化为user.FirstName.Contains((FirstName ?? ""))。

标签: c# wpf entity-framework linq-to-objects unit-of-work


【解决方案1】:

我想您可以将最后一段代码简化为:

List<User> users = UnitOfWork.UserRepository.Get(
           user =>
           ( String.IsNullOrEmpty( FirstName ) || user.FirstName.Contains( FirstName ) ) &&
           ( String.IsNullOrEmpty( LastName ) || user.LastName.Contains( LastName ) ) 
           ).ToList();

【讨论】:

    【解决方案2】:

    首先,您可以创建一个辅助函数来从主代码中取出条件

    public bool FilterColumn(string columnData, string filterData) 
    {
        return String.IsNullOrEmpty(filterData) || columnData.Contains(filterData);
    }
    

    然后可以这样使用

    List<User> users = UnitOfWork.UserRepository.Get(
               user => FilterColumn(user.FirstName, FirstName) &&
                       FilterColumn(user.LastName, LastName)).ToList()
    

    假设这段代码会受到用户输入的限制,您还可以使用反射来帮助一些(假设过滤器是类的本地,如示例中)

      private bool FilterColumn(User user, string columnName) 
      {
         var filterValue = (string) GetType ().GetProperty (columnName).GetValue (this);
         var userValue = (string) GetType ().GetProperty (columnName).GetValue (user);
    
         return string.IsNullOrWhiteSpace (userValue) || userValue.Contains (filterValue);
      }
    

    然后你可以创建一个聚合函数来收集列

      public bool FilterByColumnNames(User user, params string[] columns) 
      {
         return columns.Aggregate (true, (result, columnValue) => FilterColumn (user, columnValue));
      }
    

    这个方法可以如下使用

    var result = FilterByColumnNames(User user, "FirstName", "LastName");
    

    现在,这对重构不是很友好,所以我们将使用表达式构造更多的辅助函数

      public String ToColumnName(Expression<Func<User,string>> column)
      {
         return ((MemberExpression)column.Body).Member.Name;
      }
    
      public bool FilterByColumns(User user, params Expression<Func<User,string>>[] columns) 
      {
         return FilterByColumnNames (user, columns.Select (ToColumnName).ToArray());
      }
    

    然后可以这样使用

         var x = FilterByColumns (User, 
                    u => u.FirstName,
                    u => u.LastName);
    

    现在,这是一个未优化的版本,如果性能是一个问题,您可以更深入地挖掘表达式以创建查找的优化版本,但对于大多数与用户输入相关的事情,这应该足够快。

    【讨论】:

      猜你喜欢
      • 2020-10-03
      • 1970-01-01
      • 2022-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-30
      • 2020-04-18
      • 1970-01-01
      相关资源
      最近更新 更多