I\'m in the process of creating a more elaborate filtering system for this huge project of ours. One of the main predicates is being able to pass comparations through a string p
To generate expression, that would be translated to SQL (eSQL) you should generate Expression
manually. Here is example for GreaterThan filter creating, other filters can be made with similar technique.
static Expression> CreateGreaterThanExpression(Expression> fieldExtractor, decimal value)
{
var xPar = Expression.Parameter(typeof(T), "x");
var x = new ParameterRebinder(xPar);
var getter = (MemberExpression)x.Visit(fieldExtractor.Body);
var resultBody = Expression.GreaterThan(getter, Expression.Constant(value, typeof(decimal)));
return Expression.Lambda>(resultBody, xPar);
}
private sealed class ParameterRebinder : ExpressionVisitor
{
private readonly ParameterExpression _parameter;
public ParameterRebinder(ParameterExpression parameter)
{ this._parameter = parameter; }
protected override Expression VisitParameter(ParameterExpression p)
{ return base.VisitParameter(this._parameter); }
}
Here is the example of usage. (Assume, that we have StackEntites
EF context with entity set TestEnitities of TestEntity
entities)
static void Main(string[] args)
{
using (var ents = new StackEntities())
{
var filter = CreateGreaterThanExpression(x => x.SortProperty, 3);
var items = ents.TestEnitities.Where(filter).ToArray();
}
}
Update:
For your creation of complex expression you may use code like this:
(Assume have already made CreateLessThanExpression
and CreateBetweenExpression
functions)
static Expression> CreateFilterFromString(Expression> fieldExtractor, string text)
{
var greaterOrLessRegex = new Regex(@"^\s*(?\>|\<)\s*(?\d+(\.\d+){0,1})\s*$");
var match = greaterOrLessRegex.Match(text);
if (match.Success)
{
var number = decimal.Parse(match.Result("${number}"));
var sign = match.Result("${sign}");
switch (sign)
{
case ">":
return CreateGreaterThanExpression(fieldExtractor, number);
case "<":
return CreateLessThanExpression(fieldExtractor, number);
default:
throw new Exception("Bad Sign!");
}
}
var betweenRegex = new Regex(@"^\s*(?\d+(\.\d+){0,1})\s*-\s*(?\d+(\.\d+){0,1})\s*$");
match = betweenRegex.Match(text);
if (match.Success)
{
var number1 = decimal.Parse(match.Result("${number1}"));
var number2 = decimal.Parse(match.Result("${number2}"));
return CreateBetweenExpression(fieldExtractor, number1, number2);
}
throw new Exception("Bad filter Format!");
}