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

4

6

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.

Mciver answered 17/5, 2013 at 2:54 Comment(2)
POST some of your code here.Canary
Do you have a restriction that you should ONLY use Expression?Democratic
M
7

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)

Mciver answered 17/5, 2013 at 14:7 Comment(0)
G
2

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

Gromwell answered 24/5, 2018 at 4:14 Comment(1)
thanks. Answered this: #63524688Berfield
A
2

You can pass Type in Expression.Constant:

ConstantExpression constant = Expression.Constant(value, member.Type);
BinaryExpression equalExpression = Expression.Equal(member, constant);
Airtoair answered 13/10, 2021 at 9:23 Comment(0)
N
0

You should be using DateTime.Parse or, better, DateTime.ParseExact to convert your string to date. So, Expression.Call.

If you want to convert it to null date if the string is null, you can use Expression.Condition.
If you want to make the result nullable, I believe Expression.Convert can do that.

So something like (pseudocode):

Condition(
    Equals(yourStringExpression, null),
    Constant(null, typeof(DateTime?)),
    Convert(
        Call(DateTime.ParseExact, yourStringExpression, ...),
        typeof(DateTime?)
    )
)
Newborn answered 17/5, 2013 at 3:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.