Introduction
In the first part, I presented a small JSON object model that can be used as a way to preserve the structure of a filter (used by jqGrid). In this second part, we'll take the model and convert it to a server-side filter.
Using the Code
So here are the entities behind the design:
public class Group
{
public GroupOperator Operator { get; set; }
public List<Rule> Rules { get; set; }
public List<Group> Groups { get; set; }
}
public class Rule
{
public string Field { get; set; }
public RuleOperator Operator { get; set; }
public string Data { get; set; }
}
Using these classes, we can replicate any filter created on the client side. In terms of LINQ, the Rule is equivalent to a lambda expression and the Group
class is equivalent to an expression tree. We can therefore write the methods that translate the model into System.Linq.Expressions.Expression
:
From Rule to lambda expression:
public Expression ToExpression(Type parameterType, ParameterExpression param) {
PropertyInfo pi = null;
MemberExpression member = null;
if (this.Field.Contains(".")) {
....
}
else {
pi = parameterType.GetProperty(this.Field);
member = Expression.PropertyOrField(param, this.Field);
}
ConstantExpression constant = this.Operator == RuleOperator.IsNull ||
this.Operator == RuleOperator.NotNull
? Expression.Constant(null, pi.PropertyType)
: Expression.Constant(this.CastDataAs(pi.PropertyType), pi.PropertyType);
switch(this.Operator) {
case RuleOperator.IsNull: case RuleOperator.Equals:
return Expression.Equal(member, constant);
....
}
return null;
}
From Group to expression tree:
public Expression<func><t, bool> ToExpressionTree<t>(){
Type t = typeof(T);
ParameterExpression param = Expression.Parameter(t, "p");
Expression body = GetExpressionFromSubgroup(this, t, param);
if (body == null)
return null;
else
return Expression.Lambda<func<t, bool>>(
body,
new ParameterExpression[] { param }
);
}
protected Expression GetExpressionFromSubgroup
(Group subgroup, Type parameterType,ParameterExpression param) {
Expression body = null;
.....
return body;
}
}
I built a small helper called WebHelper
to help me with the serialization and deserialization. To put it all in one, I also added the JSONToExpressionTree
method that converts the serialized JSON into an expression tree.
So let's run some tests to see if it all goes well! We will need a simple domain:
public class Country {
public Country() { }
public int Id { get; set; }
public string Name { get; set; }
public Continent Continent { get; set; }
}
public class Continent {
public Continent() { }
public string Name { get; set; }
public IList<country> Countries { get; set; }
}
And a filter:
Group g = new Group() { Operator = GroupOperator.And };
g.Rules.Add(new Rule() { Field = "Continent.Name",
Operator = RuleOperator.StartsWith, Data = "E" });
Conclusion
Hope you enjoyed this. The next article will merge the two in an easy to use application.
Link
Part 1 of creating a dynamical filtering mechanism in C#
History
- 16th September, 2010: Initial post