Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Expression.Equal - How to Compare Nullable and Non Nullable fields?

I have a nullable datetime field and I have to convert the string date field to a nullable datetime type (using Expression)....I did this using the below.

 Expression.Constant(Convert.ChangeType(value, Nullable.GetUnderlyingType(memberAccess.Type)));.

The memberAccess (mentioned above) is of type member expression. (From LinqExtensions.cs) Now In the code I am using Expression.Equal Method.

Expression.Equal(memberAccess, filter); 

This fails here, as memberaccess type is nullable but filter.type is not nullable...

Even if I try to convert the member access type to nullable using

ConstantExpression test = Expression.Constant(Nullable.GetUnderlyingType(memberAccess.Type)),

the Type is Runtime and not DateTime.

How to use Expression.Equal to compare nullable & non nullable field? IS there any way to convert the string type to a nullable datetime field? Either one of this will resolve my issue.

like image 794
user2325247 Avatar asked Mar 23 '23 22:03

user2325247


2 Answers

Ok..I did this way.

First Converted the type (string to datetime)

filter = Expression.Constant(
    Convert.ChangeType(value, memberAccess.Type.GetGenericArguments()[0]));

then converted this expression to the desired type

Expression typeFilter = Expression.Convert(filter, memberAccess.Type);

Then used Expression.Equal(memberAccess, typeFilter)...

(memberAccess is MemberExpression and it takes the property type from model)

like image 128
user2325247 Avatar answered Apr 25 '23 18:04

user2325247


If you have values Nullable values other than dates, This is how You can create an Expression tree for nullable types, suppose you have a nullable field BoardId, you can create expression tree dynamically like this

var nameValue="BoardId=111";

 public static Expression<Func<T, bool>> BuildWhereExpression<T>(string nameValueQuery ) where  T : class 
        {
            Expression<Func<T, bool>> predicate = null;
            PropertyInfo prop = null;
            var fieldName = nameValueQuery.Split("=")[0];
            var fieldValue = nameValueQuery.Split("=")[1];
            var properties = typeof(T).GetProperties();
            foreach (var property in properties)
            {
                if (property.Name.ToLower() == fieldName.ToLower())
                {
                    prop = property;
                }
            } 
            if (prop != null)
            {
                var isNullable = prop.PropertyType.IsNullableType();
                var parameter = Expression.Parameter(typeof(T), "x");
                var member = Expression.Property(parameter, fieldName); 

                if (isNullable)
                {
                    var filter1 =
                        Expression.Constant(
                            Convert.ChangeType(fieldValue, member.Type.GetGenericArguments()[0]));
                    Expression typeFilter = Expression.Convert(filter1, member.Type);
                    var body = Expression.Equal(member, typeFilter);  
                    predicate = Expression.Lambda<Func<T, bool>>(body, parameter);  
                }
                else
                {
                    if (prop.PropertyType == typeof(string) && likeOerator.ToLower() == "like")
                    {
                        var parameterExp = Expression.Parameter(typeof(T), "type");
                        var propertyExp = Expression.Property(parameterExp, prop);
                        MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
                        var someValue = Expression.Constant(fieldValue, typeof(string));
                        var containsMethodExp = Expression.Call(propertyExp, method, someValue);
                        predicate = Expression.Lambda<Func<T, bool>>(containsMethodExp, parameterExp);
                    }
                    else
                    {
                        var constant = Expression.Constant(Convert.ChangeType(fieldValue, prop.PropertyType));
                        var body = Expression.Equal(member, constant);  
                        predicate = Expression.Lambda<Func<T, bool>>(body, parameter); `enter code here`
                    }
                }
            }
            return predicate;
        }

1- This Solution first checks for the Nullable value and generate the expression. This is How you can determine if the type is Nullable. I have created an extension method for that purpose

public static bool IsNullableType(this Type type)
    {
        return type.IsGenericType && (type.GetGenericTypeDefinition().Equals(typeof(Nullable<>)));
    }

2- the second step is to check the type if its string then create an expression for a string.

3- the Third step is to check is value is not nullable not string then create an expression using equal

like image 40
Aamir Avatar answered Apr 25 '23 19:04

Aamir