Building Dynamic Queries in LINQ Expression
// Sample query to generate
var result = people.AsQueryable().Where(x =>
(DateTime)x.Value["DOB"] <=
DateTime.Parse("7/1/1995"));
// Start
var people = new List<Dictionary<string, object>>();
//The first step is to build the base parameter of the lambda expression:
var parameter = Expression.Parameter(typeof(Dictionary<string,object>), "x");
//In order to query the list of dictionaries, you need a way to interrogate the dictionary values with either a method or property.
//Because you're using a dictionary, you'll use the item property.
//The next step is to use reflection to get information on the item property:
var propertyInfo = typeof(Dictionary<string, object>).GetProperty("Item");
//Next, you need a constant value that will be compared to a dictionary element.
//In this case, it will be a DateTime value to compare to the DOB field
var value = Expression.Constant(
DateTime.Parse("7/1/1995")
);
//Next, you have to have a way to reference a dictionary element.
//In addition, because all of the elements are object values, you need a way to convert to the appropriate data type.
//The following code handles this task:
var arguments = new List<Expression> {
Expression.Constant("DOB") };
var index =
Expression.Convert(Expression.MakeIndex(parameter,
propertyInfo, arguments), typeof(DateTime));
//Once you have all of that, you can create the expression and lambda:
var expression =
Expression.MakeBinary(ExpressionType.LessThanOrEqual,
index, value);
var lambda = Expression.Lambda<Func<Dictionary<string, object>,
bool>>(expression, parameter);
//The following is the dynamic lambda's string representation:
//{x => (Convert(x.Item["DOB"]) <= 7/1/1995 12:00:00 AM)}
//Now, you can use the dynamically generated lambda:
var result = people.AsQueryable().Where(lambda);
//If you need to implement additional criteria, you can simply define another expression and then, with an existing expression, invoke the And or Or methods. Leveraging the previous code as an example it looks like this:
//expression = Expression.And(expression, newExpression);