如何使用LINQ重构发送到DataGridView的Rows上的过滤器

时间:2015-02-04 19:34:57

标签: c# linq datagridview

**是否有更简单的方法以这种方式过滤DataGridView中的行? 因为它看起来有点复杂 **

    private void Reread()
    {
        string nameFilter = txtSearch.Text;
        string addressFilter = comboBox1.SelectedIndex > 0 ? comboBox1.Text : "";
        string depFilter = comboBox2.SelectedIndex > 0 ? comboBox2.Text : "";
        DateTime? birthdate = chkBirthdate.Checked ? dateTimePicker1.Value.Date : (DateTime?) null;
        DateTime? fromDate = chkRange.Checked ? dateTimePicker2.Value.Date : (DateTime?)null;
        DateTime? toDate = chkRange.Checked ? dateTimePicker3.Value.Date : (DateTime?)null;

        using (DbDataContext db = new DbDataContext())
        {
            var result = from p in db.Persons
                         where
                            (nameFilter.Length > 0 && p.FullName.Contains(nameFilter) || nameFilter.Length == 0)
                         && (addressFilter.Length > 0 && p.Address == addressFilter || addressFilter.Length == 0)
                         && (depFilter.Length > 0 && p.Department == depFilter || depFilter.Length == 0)
                         && (birthdate == null || (birthdate != null && p.Birthdate == birthdate))
                         && ((fromDate == null || toDate == null) || (fromDate != null && toDate != null && p.Birthdate >= fromDate && p.Birthdate <= toDate))

                         select p;

            var resultData = result.ToList();

            dataGridView1.DataSource = resultData;
        }

1 个答案:

答案 0 :(得分:0)

要求改进工作代码(easier)的问题更适合http://codereview.stackexchange.com,因为它们意味着一定程度的意见。我相信你的代码需要一些设计改进,并且当前形式的可选Linq谓词将导致Sql查询,当Persons表中有大量行时,它们表现不佳。

  • 将解析用户输入(查询过滤器)的问题与实际查询数据的行为分开。通常,这将被分成不同的类,甚至是不同的程序集,代表这些不同的层/关注点(例如表示层和数据/存储库层)
  • 在点击数据库之前引入验证。没有过滤器的查询将尝试检索所有Person行,浪费IO并可能使应用程序崩溃OutOfMemoryException。此外,您可以将验证分成单独的方法或类。
  • 根据我的评论,'可选'谓词过滤器模式导致Sql沿着@filter <> null AND column = @filter OR @filter IS NULL行,这将导致较差的Sql Query性能,并将缓存不适合其他过滤器排列的计划。你想在这里做的是完全省略任何不需要的谓词(即用户将过滤器留空的地方)。我使用下面IQueryable的简单组合来执行此操作,但对于更高级的情况,您需要转到PredicateBuilderDynamicLinq以获得更复杂的谓词。

IList<Person> FindPersons(string nameFilter, string addressFilter, 
                          DateTime? birthdate, .. etc)
{
   using (var db = new DbDataContext())
   {
     var query = db.Persons.AsQueryable();
     if (!string.IsNullOrWhitespace(nameFilter))
     {
        query = query.Where(p => p.FullName.Contains(nameFilter));
     }
     if (!string.IsNullOrWhitespace(addressFilter))
     {
        query = query.Where(p => p.Address == addressFilter);
     }
     if (!string.IsNullOrWhitespace(depFilter))
     {
        query = query.Where(p => p.Department == depFilter);
     }
     if (birthdate.HasValue)
     {
        query = query.Where(p => p.Birthdate == birthdate);
     }
     query = query.Take(1000); // Sanity, limit the rows

     return query.ToList();
   }
}

protected void OnSearchPersonClick()
{
    // Parsing
    var nameFilter = txtSearch.Text;
    var addressFilter = comboBox1.SelectedIndex > 0 ? comboBox1.Text : "";
    DateTime? birthdate = chkBirthdate.Checked 
           ? dateTimePicker1.Value.Date 
           : (DateTime?) null;       
    // etc

    // Validation
    if (string.IsNullOrWhitespace(nameFilter) 
        && string.IsNullOrWhitespace(addressFilter) 
        && !(birthdate.HasValue)) // etc
    {
        ShowErrorMessageToUser("Please provide at least one filter");
        return;
    }

    // Bind
    dataGridView1.DataSource = FindPersons();
}