I recently came across a requirement where I had to filter
entity objects. Consider the following scenario:
I have a class called - Product.
public
class Product
{
public string Name { get; set; }
public string Code { get; set; }
public string Type { get; set; }
public bool IsTaxable { get;
set; }
public
Product(string name, string
code, bool isTaxable)
{
this.Name
= name;
this.Code
= code;
this.IsTaxable
= isTaxable;
}
}
Let’s first create list of products and populate it.
List<Product> products = new
List<Product>();
products.Add(new Product("ABC",
"a", true));
products.Add(new Product("PQR",
"p", false));
products.Add(new Product("XYZ",
"x", true));
If I want to filter Products which are taxable, I can just
get them by using the following Lambda expression statement:
List<Product> filteredList =
EntityFilter.FilterRecords(prods, "IsTaxable",
true).ToList();
Very easy, isn’t it?
The above requirement is pretty much straightforward. Let’s
go beyond it. Consider, you’re making a search webpart and you need to allow
user to filter products based on any attribute. They should be able to filter
by Name or Code or any other attribute. In this scenario, you don’t know on
which attribute the user is going to filter the records.
So will you write the code as follows?
if
(attributeName == "Name")
filteredProducts = products.FindAll(p =>
p.Name == attributeValue);
else
if (attributeName == "Code")
filteredProducts = products.FindAll(p =>
p.Code == attributeValue);
else
if (attributeName == "IsTaxable")
filteredProducts = products.FindAll(p =>
p.IsTaxable == Convert.ToBoolean(attributeValue));
Don’t do this!! You’ll end up making a mess of your existing
code.
Then how shall we proceed? Well, this is where the blog starts:
Let’s create a class, called “EntityFilter”.
public
class EntityFilter
{
public static IQueryable<T>
FilterRecords<T>(IQueryable<T>
source, string propertyName, object value)
{
ParameterExpression
parameter = Expression.Parameter(typeof(T));
Expression
predicate = Expression.Constant(true);
Expression
expProperty = Expression.PropertyOrField(parameter,
propertyName);
Expression
expFilter = Expression.Equal(expProperty, Expression.Constant(value));
var
lambda = Expression.Lambda<Func<T, bool>>(expFilter,
parameter);
return
source.Where(lambda);
}
}
That’s all. You’re done.
Now just fire a following statement
to filter records:
filteredProducts
= EntityFilter.FilterRecords(products.AsQueryable(), "Name",
"ABC").ToList();
OR
filteredProducts
= EntityFilter.FilterRecords(products.AsQueryable(), "Code",
"x").ToList();
OR
filteredProducts
= EntityFilter.FilterRecords(products.AsQueryable(), "IsTaxable",
true).ToList();
Looks amazing, isn't it?
Let's go ahead and dissect each statement one at a time.
You first start off with a parameter expression of type “T”.
Here, “T” can be any type or class:
ParameterExpression parameter = Expression.Parameter(typeof(T));
The next line is to define, predicate:
Expression predicate = Expression.Constant(true);
The next step is to build the body of lambda expressions
which happens to be property expression and filter:
Expression expProperty = Expression.PropertyOrField(parameter,
propertyName);
Expression expFilter = Expression.Equal(expProperty,
Expression.Constant(value));
Now, we need to build the lambda expression which combines
the body with the parameter as follows:
var
lambda = Expression.Lambda<Func<T, bool>>(expFilter,
parameter);
The final step is to filter the source with the dynamic
lambda expression:
return
source.Where(lambda);
Isn’t this completely dynamic? You can filter any entity
with any attribute. Why not have this utility class in every solution you
build!
There are always different ways to write code but there is
only one way to write awesome code!!