0

I have a class called User in which there is a field wherein the user can send any data type. Currently we are sending int, double and string.

Since the field is dynamic meaning the field name could be anything we are using expression trees. The issue I am facing now is if the field is null in the select query or the field value then it throws error.

Below is my code:

Expression<Func<User, bool>> comparison = null;

if (Value.GetType() == typeof(int))
    comparison = EvaluateRules<int>(attributeName);
else if (Value.GetType() == typeof(double))
    comparison = EvaluateRules<double>(attributeName);
else if (Value.GetType() == typeof(string))
    comparison = EvaluateRules<string>(attributeName);


private Expression<Func<User, bool>> EvaluateRules<T>(string attributeName)
{
    var attributeParameter = Expression.Parameter(typeof(User), "user");
    Expression<Func<User, bool>> comparison = null;
    var parseMethod = typeof(T).GetMethod("Parse", new[] { typeof(string) });

    switch (policyOperator)
    {
        case Operator.GreaterThanOrEqual:
            if (Value.GetType() != typeof(string))
                comparison = Expression.Lambda<Func<User, bool>>(
                                    Expression.GreaterThanOrEqual(
                                        Expression.Call(parseMethod, Expression.Property(attributeParameter, attributeName)),
                                        Expression.Constant(Value)),
                                        attributeParameter);
            break;
    }

    return comparison;
}

resultUsers = from user in users.AsQueryable().Where(comparison) select user

Any clues??

Thanks for your time.

Anil Jain
  • 85
  • 2
  • 14
  • `The issue I am facing now is if the field is null in the select query or the field value then it throws error.` What exception does it throw? On what line? – mjwills Sep 04 '17 at 09:59
  • It says "Value cannot be null. Parameter name: String". This error is thrown in the below statement resultUsers = from user in users.AsQueryable().Where(comparison) select user – Anil Jain Sep 04 '17 at 11:39
  • why dont you handle the null value separately, instead of invoking a Parse method on it?E.g. Expression.OrElse(Expression.Equal(Expression.Property(attributeParameter, attributeName), Expression.Constant(null, typeof(T))), ...graterthan...) btw is it going to the db? if not, why are you using expression trees, instead of plain Func<>s? – MBoros Sep 05 '17 at 20:08
  • @MBoros .... Thanks for your reply. Parse method is required because the column value will contain numeric while the column type itself is string. We are using mongo db. Of course we are getting the user list from mongo db. The reason for using expression trees is because we do not know the column name in advance. This column would be dynamically binded at run time. – Anil Jain Sep 06 '17 at 16:07

1 Answers1

3

Thanks for your reply. I was able to solve it with the below code. Posting it in case it helps someone.

ParameterExpression attributeParameter = Expression.Parameter(typeof(User), "user");
MemberExpression attribute = Expression.Property(attributeParameter, attributeName);
BinaryExpression nullCheck = Expression.NotEqual(attribute, Expression.Constant(null, typeof(object)));
BinaryExpression condition = null;

 switch (policyOperator)
{
    case Operator.GreaterThanOrEqual:
    if (Value.GetType() != typeof(string))
        condition = Expression.GreaterThanOrEqual(Expression.Call(parseMethod, 
                        Expression.Property(attributeParameter, attributeName)), 
                            Expression.Constant(Value));

    .
    .
}

return Expression.Lambda<Func<User, bool>>(Expression.AndAlso(nullCheck, condition), attributeParameter);                           
Anil Jain
  • 85
  • 2
  • 14
  • Just as a side note, if you want to keep the code maintainable, forget about low level Expr API, and combine expressions generated by the compiler with (i advertisr myself :P): https://stackoverflow.com/questions/29448432/pass-expression-parameter-as-argument-to-another-expression/29471092#29471092 – MBoros Sep 08 '17 at 05:59
  • @MBoros .... I above code is completely a separate method which returns the lambda expression. This method supports 5 operations GreaterThanOrEqual etc.. If its possible to make the code more maintainable please let me know. – Anil Jain Sep 10 '17 at 12:47
  • https://weblogs.asp.net/scottgu/dynamic-linq-part-1-using-the-linq-dynamic-query-library this seems to be less and cleaner code... all the complexity is hidden away, and you dont have to maintain it. – MBoros Sep 11 '17 at 19:41
  • I suppose this code won't handle non-nullable types. Is there a well-known solution that considers just skipping non-nullable types? – Sergey Nikitin Dec 11 '19 at 22:45