saimmm0710
saimmm0710

Reputation: 95

Generic filter class using LINQ

I have a filter politique throughout the application that use EntityFramework and winform, now i need to design a class to facilitate the filtering, like that

public class TextPredicatFilter<T>
{ 
    List<T> _list;
    List<CheckedPredicat> _listPredicat= new List<CheckedPredicat>();
    bool _active = true; 
    public TextPredicatFilter(BindingSource bs ,TextBox txtFilter, List<T> bindingList)
    {
        _list = bindingList;

        txtFilter.TextChanged += delegate
        {
            if (!_active)
                return; 
            foreach(CheckedPredicat prd in _listPredicat)
            {
                if(prd.CheckControl.Checked)
                {
                     bs.DataSource = new BindingList<T>(_list.Where(t=>t.GetType().GetProperty(prd.ColumnName).GetConstantValue().ToString() == txtFilter.Text).ToList<T>());
                }
            }
        };
    }
    public void Add(CheckedPredicat chkPredicat)
    {
        _listPredicat.Add(chkPredicat);
    }}

public class CheckedPredicat
{
    public RadioButton CheckControl { get; set; }
    public string ColumnName { get; set; }
    public bool UseLike { get; set; }       
}

but this does't work! any idea?

Upvotes: 1

Views: 147

Answers (2)

Steve Cooper
Steve Cooper

Reputation: 21470

You might want to check out Dynamic Linq, which lets you write filters like this;

using System.Linq.Dynamic; //Import the Dynamic LINQ library

var result = myQuery
    .Where("Field1=\"SomeValue\"")
    .Select("new (Field1, Field2)");

I think you can write the startswith/endswith direct in the WHERE clause; something like

var result = myQuery
   .Where("Field1.StartsWith(\"somevalue\") || Field1.EndsWith(\"somevalue\")")

but I'm not sure.

Upvotes: 1

Gert Arnold
Gert Arnold

Reputation: 109079

First, make this independent of any UI implementation. You don't need BindingSources or RadioButtons to build a dynamic database query. Use the original data, filter them, and then re-bind the result to whichever UI framework you happen to use today... or tomorrow.

Secondly, keep it simple. All you need is a collection of column names, their search terms and booleans. You're only filtering. That doesn't require a whole new class TextPredicatFilter doing the work.

Thirdly, to answer your question, use Dynamic LINQ to build the query. (Also recommended by Steve while I was preparing this).

Let's say you have this class:

public class Predicate
{
    public string ColumnName  { get; set; }
    public string FilterValue { get; set; }
    public bool UseLike { get; set; }
}

Then all the code to build the query could look like this:

using System.Linq.Dynamic;

IQueryable<Company> companies = context.Companies;

var predicates = new Predicate[]
{
    new Predicate { ColumnName = "Name", FilterValue = "o", UseLike = true },
    new Predicate { ColumnName = "Code", FilterValue = "c", UseLike = false },
};

foreach (var pred in predicates)
{
    var predicateString = pred.UseLike
                            ? "{0}.Contains(@{1})"
                            : "{0} = @{1}";
    companies = companies
        .Where(string.Format(predicateString, pred.ColumnName, 0), pred.FilterValue);
}

Now you can bind companies (probably with ToList()) to a BindingList or whatever type of display you want to use.

Upvotes: 2

Related Questions