4
votes

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.

4
POST some of your code here.Vond Ritz
Do you have a restriction that you should ONLY use Expression?jacob aloysious

4 Answers

5
votes

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)

2
votes

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

0
votes

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?)
    )
)
0
votes

You can pass Type in Expression.Constant:

ConstantExpression constant = Expression.Constant(value, member.Type);
BinaryExpression equalExpression = Expression.Equal(member, constant);