Generating a LINQ query using Expression Trees

c# expression-trees lambda linq

Question

Update

Thanks to Marc's help the AlphaPagedList class is now available on CodePlex if anyone is interested

Original

I'm trying to create an expression tree to return elements that start with a given charecter.

IList<char> chars = new List<char>{'a','b'};
IQueryable<Dept>Depts.Where(x=> chars.Contains(x.DeptName[0]));

I want this to be used on any IEnumerable where I provide a lamdba to the property to select on eg:

Depts.Alpha(x=>x.DeptName, chars);

I've been trying this but having no luck at all, any help?

public static IQueryable<T> testing<T>(this IQueryable<T> queryableData, Expression<Func<T,string>> pi, IEnumerable<char> chars)
{
// Compose the expression tree that represents the parameter to the predicate.

ParameterExpression pe = Expression.Parameter(queryableData.ElementType, "x");
ConstantExpression ch = Expression.Constant(chars,typeof(IEnumerable<char>));
// ***** Where(x=>chars.Contains(x.pi[0])) *****
// pi is a string property
//Get the string property

Expression first = Expression.Constant(0);
//Get the first character of the string
Expression firstchar = Expression.ArrayIndex(pi.Body, first);
//Call "Contains" on chars with argument being right
Expression e = Expression.Call(ch, typeof(IEnumerable<char>).GetMethod("Contains", new Type[] { typeof(char) }),firstchar);


MethodCallExpression whereCallExpression = Expression.Call(
    typeof(Queryable),
    "Where",
    new Type[] { queryableData.ElementType },
    queryableData.Expression,
    Expression.Lambda<Func<T, bool>>(e, new ParameterExpression[] { pe }));
// ***** End Where *****

return (queryableData.Provider.CreateQuery<T>(whereCallExpression));
}

Accepted Answer

Something like (EDITED after re-reading the question) - but note that Expression.Invoke doesn't work on EF in 3.5SP1 (but it is fine in LINQ-to-SQL):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

class Dept
{
    public string DeptName { get; set; }
}
public static class Program
{
    static void Main()
    {
        IList<char> chars = new List<char>{'a','b'};
        Dept[] depts = new[] { new Dept { DeptName = "alpha" }, new Dept { DeptName = "beta" }, new Dept { DeptName = "omega" } };
        var count = testing(depts.AsQueryable(), dept => dept.DeptName, chars).Count();
    }

    public static IQueryable<T> testing<T>(this IQueryable<T> queryableData, Expression<Func<T,string>> pi, IEnumerable<char> chars)
    {
        var arg = Expression.Parameter(typeof(T), "x");
        var prop = Expression.Invoke(pi, arg);
        Expression body = null;
        foreach(char c in chars) {
            Expression thisFilter = Expression.Call(prop, "StartsWith", null, Expression.Constant(c.ToString()));
            body = body == null ? thisFilter : Expression.OrElse(body, thisFilter);
        }
        var lambda = Expression.Lambda<Func<T, bool>>(body ?? Expression.Constant(false), arg);
        return queryableData.Where(lambda);
    }
}



Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why