Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting error : The binary operator Equal is not defined for the types 'System.Guid' and 'System.String'

This is My Expression Class

        public static class ExpressionBuilder
    {
        private static MethodInfo containsMethod = typeof(string).GetMethod("Contains");
        private static MethodInfo startsWithMethod = typeof(string).GetMethod("StartsWith", new Type[] { typeof(string) });
        private static MethodInfo endsWithMethod = typeof(string).GetMethod("EndsWith", new Type[] { typeof(string) });


        public static Expression<Func<T,
        bool>> GetExpression<T>(IList<Filter> filters)
        {
            if (filters.Count == 0)
                return null;

            ParameterExpression param = Expression.Parameter(typeof(T), "t");
            Expression exp = null;

            if (filters.Count == 1)
                exp = GetExpression<T>(param, filters[0]);
            else if (filters.Count == 2)
                exp = GetExpression<T>(param, filters[0], filters[1]);
            else
            {
                while (filters.Count > 0)
                {
                    var f1 = filters[0];
                    var f2 = filters[1];

                    if (exp == null)
                        exp = GetExpression<T>(param, filters[0], filters[1]);
                    else
                        exp = Expression.AndAlso(exp, GetExpression<T>(param, filters[0], filters[1]));

                    filters.Remove(f1);
                    filters.Remove(f2);

                    if (filters.Count == 1)
                    {
                        exp = Expression.AndAlso(exp, GetExpression<T>(param, filters[0]));
                        filters.RemoveAt(0);
                    }
                }
            }

            return Expression.Lambda<Func<T, bool>>(exp, param);
        }

        private static Expression GetExpression<T>(ParameterExpression param, Filter filter)
        {
            MemberExpression member = Expression.Property(param, filter.PropertyName);
            ConstantExpression constant = Expression.Constant(filter.Value);

            switch (filter.Operation)
            {
                case Op.Equals:
                    return Expression.Equal(member, Expression.Call(Expression.Convert(Expression.Constant(search.RetrieveGuid), typeof(object)), typeof(object).GetMethod("ToString"))), constant);

                case Op.GreaterThan:
                    return Expression.GreaterThan(member, constant);

                case Op.GreaterThanOrEqual:
                    return Expression.GreaterThanOrEqual(member, constant);

                case Op.LessThan:
                    return Expression.LessThan(member, constant);

                case Op.LessThanOrEqual:
                    return Expression.LessThanOrEqual(member, constant);

                case Op.Contains:
                    return Expression.Call(member, containsMethod, constant);

                case Op.StartsWith:
                    return Expression.Call(member, startsWithMethod, constant);

                case Op.EndsWith:
                    return Expression.Call(member, endsWithMethod, constant);
            }

            return null;
        }

        private static BinaryExpression GetExpression<T>
        (ParameterExpression param, Filter filter1, Filter filter2)
        {
            Expression bin1 = GetExpression<T>(param, filter1);
            Expression bin2 = GetExpression<T>(param, filter2);

            return Expression.AndAlso(bin1, bin2);
        }
    }

when i generate Expression by this code

 delegExpFilters = EntityExpression.ExpressionBuilder.GetExpression<Contact>(domainFilter).Compile();

my domainFilter Contains a list records with Property field name ,operator, and its value and my field is GUID

when i call GetExpression it gives me error The binary operator Equal is not defined for the types 'System.Guid' and 'System.String'

like image 523
Fraz Zaki Avatar asked Mar 13 '17 15:03

Fraz Zaki


1 Answers

You are not converting filter value (which is string) to appropriate type:

ConstantExpression constant = Expression.Constant(filter.Value);

Consider you have filter for integer property named Amount:

var filter = new Filter {
   PropertyName = "Amount",
   Operation = Op.GreaterThan,
   Value = "42"
};

Your code will generate expression which equivalent of following code

contract.Amount > "42"

Such integer comparison with string is not allowed.


You should get property type and convert filter value to that type. Here are the steps:

  1. Get type converter for property type
  2. Check whether it can convert string to property type
  3. Do conversion (that will return property value as object
  4. Create cast expression to convert property value from object to property type

Here is code of GetExpression method

var member = Expression.Property(param, filter.PropertyName);
var propertyType = ((PropertyInfo)member.Member).PropertyType;
var converter = TypeDescriptor.GetConverter(propertyType); // 1

if (!converter.CanConvertFrom(typeof(string))) // 2
   throw new NotSupportedException();

var propertyValue = converter.ConvertFromInvariantString(filter.Value); // 3
var constant = Expression.Constant(propertyValue);
var valueExpression = Expression.Convert(constant, propertyType); // 4

You should use this value expression instead of your constant expression in binary expressions which you are returning. E.g.:

case Op.LessThan:
    return Expression.LessThan(member, valueExpression);
case Op.Equal:
    return Expression.Equal(member, valueExpression);
// etc

For equality you should use binary expression as well. And now filter for Amount will be translated into

 contract.Amount > (int)42
like image 169
Sergey Berezovskiy Avatar answered Nov 16 '22 01:11

Sergey Berezovskiy