How do I build a Linq Expression Tree that compares against a generic object?

By : JTew
Source: Stackoverflow.com
Question!

I have an IQueryable and an object of type T.

I want to do IQueryable().Where(o => o.GetProperty(fieldName) == objectOfTypeT.GetProperty(fieldName))

so ...

public IQueryable<T> DoWork<T>(string fieldName)
        where T : EntityObject
{
   ...
   T objectOfTypeT = ...;
   ....
   return SomeIQueryable<T>().Where(o => o.GetProperty(fieldName) == objectOfTypeT.GetProperty(fieldName));
}

Fyi, GetProperty isn't a valid function. I need something which performs this function.

Am I having a Friday afternoon brain melt or is this a complex thing to do?


objectOfTypeT I can do the following ...

var matchToValue = Expression.Lambda(ParameterExpression
.Property(ParameterExpression.Constant(item), "CustomerKey"))
.Compile().DynamicInvoke();

Which works perfectly,now I just need the second part:

return SomeIQueryable().Where(o => o.GetProperty(fieldName) == matchValue);

By : JTew


Answers

What about:

    public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }

    }

    public Func<T, TRes> GetPropertyFunc<T, TRes>(string propertyName)
    {
        // get the propertyinfo of that property.
        PropertyInfo propInfo = typeof(T).GetProperty(propertyName);

        // reference the propertyinfo to get the value directly.
        return (obj) => { return (TRes)propInfo.GetValue(obj, null); };
    }

    public void Run()
    {
        List<Person> personList = new List<Person>();

        // fill with some data
        personList.Add(new Person { Name = "John", Age = 45 });
        personList.Add(new Person { Name = "Michael", Age = 31 });
        personList.Add(new Person { Name = "Rose", Age = 63 });

        // create a lookup functions  (should be executed ones)
        Func<Person, string> GetNameValue = GetPropertyFunc<Person, string>("Name");
        Func<Person, int> GetAgeValue = GetPropertyFunc<Person, int>("Age");


        // filter the list on name
        IEnumerable<Person> filteredOnName = personList.Where(item => GetNameValue(item) == "Michael");
        // filter the list on age > 35
        IEnumerable<Person> filteredOnAge = personList.Where(item => GetAgeValue(item) > 35);
    }

This is a way to get values of a properties by string without using of dynamic queries. The downside is al values will be boxed/unboxed.



Like so:

    var param = Expression.Parameter(typeof(T), "o");
    var fixedItem = Expression.Constant(objectOfTypeT, typeof(T));
    var body = Expression.Equal(
        Expression.PropertyOrField(param, fieldName),
        Expression.PropertyOrField(fixedItem, fieldName));
    var lambda = Expression.Lambda<Func<T,bool>>(body,param);
    return source.Where(lambda);

I have started a blog which will cover a number of expression topics, here.

If you get any problems, another option is to extract the value from objectOfTypeT first (using reflection) and then use that value in the Expression.Constant, but I suspect it'll be fine "as is".



From what I can see so far it's going to have to be something like ...

IQueryable<T>().Where(t => 
MemberExpression.Property(MemberExpression.Constant(t), fieldName) == 
ParameterExpression.Property(ParameterExpression.Constant(item), fieldName));

While I can get this to compile it's not quite executing the way it is required.

By : JTew


This video can help you solving your question :)
By: admin