How to Type Cast dynamically to string while using Contains in Dynamic LINQ?

c# dynamic-linq entity-framework linq linq-to-entities

Question

I want to use Dynamic LINQ Query to Search with some text in all Properties in a class. i am using following function to create expression. I am passing property name and search text to the method. In that method if the property type is String then it is working fine. if the property type is int, DateTime, GUID. then it is not working.

As we know Contains method only for array of elements or for string. I am thinking the value to property should type cast to string. So How to do it? Solution with Explanation is help full.

i Collected code from this.

   public static Expression<Func<T, bool>> ContainsExp<T>(string propertyName, string contains)
    {
        var parameterExp = Expression.Parameter(typeof(T), "type");
        var propertyExp = Expression.Property(parameterExp, propertyName);

      MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });


        var someValue = Expression.Constant(contains, typeof(string));
        var containsMethodExp = Expression.Call(propertyExp, method, someValue);

        return Expression.Lambda<Func<T, bool>>(containsMethodExp, parameterExp);

    }
1
4
5/23/2017 12:33:14 PM

Accepted Answer

Well, you probably know that's it's not possible to use ToString() in linq to entities.

So the following question is : how can I convert other types to string.

For numeric values, you have SqlFunctions.StringConvert, but it has only overloads for double? and decimal?

For DateTime, you may find something using SqlFunctions.StringConvert after having applied SqlFunctions.DatePart on your DateTime (which probably means at least 3 call to SqlFunctions.DatePart, for year, month, day)

For Guid, I don't think there's a way to do it directly. One way (at db level, if you use Sql Server) could be to have a Computed column. The computed column could store a varchar converted representation of your GUID. Maybe there's a better way.

Anyway, here's at least a sample which should work for integer as well as string:

 public static Expression<Func<T, bool>> ContainsExp<T>(string propertyName, string contains)
        {

            //first, get the type of your property
            var propertyType = typeof(T).GetProperty(propertyName).PropertyType;
            //no change
            var parameterExp = Expression.Parameter(typeof (T), "type");
            Expression propertyExp = Expression.Property(parameterExp, propertyName);
            //if property's type is int
            if (propertyType == typeof (int))
            {
                //convert your Expression to a nullable double (or nullable decimal),
                //so that you can use SqlFunctions.StringConvert
                propertyExp = Expression.Convert(propertyExp, typeof (double?));
                //get the SqlFunctions.StringConvert method for nullable double
                var stringConvertMethod = typeof (SqlFunctions).GetMethod("StringConvert", new[] {typeof (double?)});
                //call StringConvert on your converted expression
                propertyExp = Expression.Call(stringConvertMethod , propertyExp);
            }
            //no change
            var method = typeof (string).GetMethod("Contains", new[] {typeof (string)});


            var someValue = Expression.Constant(contains, typeof (string));
            var containsMethodExp = Expression.Call(propertyExp, method, someValue);

            return Expression.Lambda<Func<T, bool>>(containsMethodExp, parameterExp);

        }
2
10/11/2013 1:01:17 PM

Popular Answer

 public static IQueryable<T> FieldsContains<T>(this IQueryable<T> query, List<string> fileds, string searchValue)
    {
        Expression predicate = null;
        var parameterExpression = Expression.Parameter(typeof(T), "type");

        foreach (string field in fileds)
        {
            var next = GetFieldContainsExpression<T>(parameterExpression, field, searchValue);

            if (predicate == null)
            {
                predicate = next;
            }
            else
            {
                predicate = Expression.Or(predicate, next);
            }
        }

        var lambda = Expression.Lambda<Func<T, bool>>(predicate, parameterExpression);

        return query.Where(lambda);
    }

    private static Expression GetFieldContainsExpression<T>(ParameterExpression parameterExpression, string field, string value)
    {
        var propertyType = typeof(T).GetProperty(field).PropertyType;
        Expression propertyExpression = Expression.Property(parameterExpression, field);

        var filterValue = Expression.Constant(value);
        var method = typeof(string).GetMethod("Contains", new[] { typeof(string) });

        //call toString first to ignore type errors(datetime, int ...)
        var toStringExpression = Expression.Call(propertyExpression, "ToString", Type.EmptyTypes);
        var containsExpression = Expression.Call(toStringExpression, method, filterValue);

        return containsExpression;
    }


Related Questions





Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow