How do I dynamically create an Expression> predicate from Expression>?

后端 未结 2 2111
误落风尘
误落风尘 2020-11-29 22:50

I trying to append where predicates and my goal is to create the same expression as:

Services.Where(s => s.Name == \"Modules\" && s.Namespace == \         


        
相关标签:
2条回答
  • 2020-11-29 23:32

    It's hard to mix compiler-generated expression trees and hand-made ones, precisely because of this sort of thing - extracting out the ParameterExpressions is tricky. So let's start from scratch:

    ParameterExpression argParam = Expression.Parameter(typeof(Service), "s");
    Expression nameProperty = Expression.Property(argParam, "Name");
    Expression namespaceProperty = Expression.Property(argParam, "Namespace");
    
    var val1 = Expression.Constant("Modules");
    var val2 = Expression.Constant("Namespace");
    
    Expression e1 = Expression.Equal(nameProperty, val1);
    Expression e2 = Expression.Equal(namespaceProperty, val2);
    var andExp = Expression.AndAlso(e1, e2);
    
    var lambda = Expression.Lambda<Func<Service, bool>>(andExp, argParam);
    

    One important aspect I've changed is the type passed to Expression.Parameter - it certainly looks like it should be a Service rather than a string.

    I've given that a try, and it seemed to work when I called lambda.Compile and executed it on a couple of sample Service objects...

    0 讨论(0)
  • 2020-11-29 23:32

    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";

    you need to determine first Property type, whether its Nullable or not

    Below code create a Dynamic tree expression for nullable and Non Nullable types

     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 讨论(0)
提交回复
热议问题