使用多列创建WHERE条件

时间:2015-02-05 12:27:02

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

我有以下方法:

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 ;
}

这只是一个&#34;简化&#34;例。实际上我还有一些&#34;列&#34;为了我的条件。

两个&#34;条件&#34;与and-operator(&amp;&amp;)链接。这意味着:

  • 必须填写姓名&amp;必须与 AND
  • 匹配
  • 必须填写第二个姓名&amp;必须匹配

这不是我想要的。使用or-operator(||)更改代码,如

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 ;
}

没有提供所需的解决方案,因为:

  • 必须填写姓名&amp;必须匹配 OR
  • 必须填写第二个姓名&amp;匹配

那么,我想要什么?

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

  • 怀特,保罗
  • 米勒,约翰
  • Miller,Lea

我期待以下结果:

  • 如果只是姓氏&#34;米勒&#34;输入我想得到这两个 记录。
  • 如果输入了姓氏和名字(&#34; Miller&#34;和#34; John&#34;)我希望只能获得一条记录。

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

这会更合适吗?

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 ;
}

这似乎有效。但随着越来越多的专栏,它肯定看起来很难看,很难阅读。有没有办法简化这项任务?

2 个答案:

答案 0 :(得分:0)

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

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

答案 1 :(得分:0)

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

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

现在,这是一个未经优化的版本,如果性能问题,您可以深入研究表达式以创建查找的优化版本,但对于大多数绑定到用户类型的事情,这应该足够快。 / p>