I am busy creating wrapper extension methods on top of Dapper and DapperExtensions. At the moment I am trying to add filtering to the GetList extension
I have figured out how to achieve what I want.
In summary:
GetList extension method.IFieldPredicate which I can use to add a filter to the SQL query to be executed. I can achieve this by using Predicates.Field(Expression> expression, Operator op, object value) .t => t.Id == id into parameters for Predicates.Field. So, conceptually, I need to pull apart the lambda expression into three parts: t => t.Id, Operator.Eq, and id.With help from @Iridium, @Eduard and @Jon, my final solution is:
public static class SqlConnectionExtensions
{
public static IEnumerable Get(this IDbConnection connection, Expression> expression) where T : class
{
using (connection)
{
connection.Open();
var binaryExpression = (BinaryExpression)((UnaryExpression) expression.Body).Operand;
var left = Expression.Lambda>(Expression.Convert(binaryExpression.Left, typeof(object)), expression.Parameters[0]);
var right = binaryExpression.Right.GetType().GetProperty("Value").GetValue(binaryExpression.Right);
var theOperator = DetermineOperator(binaryExpression);
var predicate = Predicates.Field(left, theOperator, right);
var entities = connection.GetList(predicate, commandTimeout: 30);
connection.Close();
return entities;
}
}
private static Operator DetermineOperator(Expression binaryExpression)
{
switch (binaryExpression.NodeType)
{
case ExpressionType.Equal:
return Operator.Eq;
case ExpressionType.GreaterThan:
return Operator.Gt;
case ExpressionType.GreaterThanOrEqual:
return Operator.Ge;
case ExpressionType.LessThan:
return Operator.Lt;
case ExpressionType.LessThanOrEqual:
return Operator.Le;
default:
return Operator.Eq;
}
}
}
I can now do this:
var matchingPeople = Connection.Get(p => p.MarketId == marketId);
I know how brittle this is - it will break if I pass in anything more complex, or even something that looks to be equivalent, like var matchingPeople = Connection.Get. It does solve 90% of my cases though so I am content to leave it as-is.