'Expression Tree for Any with Contains

we have a REST-API that takes a string query in the format ProductEANs.EAN, so . separated. The searchFields are parsed from a string like this: {"ProductEANs.EAN":"113"}. The base type is always known. Now I want to dynamically create a Expression Tree to query the DataSet. If the property is not a List it works but I cant get it to work with Lists. What I want to recreate is the expression: productsQuery.Where(p => p.ProductEANs.Any(e => e.EAN.Contains("113")));. This is where I am so far:

IQueryable<Product> productsQuery = _context.Products
                .Include(p => p.ProductEANs);

foreach (KeyValuePair<string, string> searchField in searchFields)
{
    if (!string.IsNullOrWhiteSpace(searchField.Value))
    {
        var parameterExpression = Expression.Parameter(typeof(Product), "product");
        var constant = Expression.Constant(searchField.Value);

        MethodCallExpression expression = null;
        Expression property = parameterExpression;

        foreach (var member in searchField.Key.Split('.'))
        {
            if (property.Type.IsGenericType &&
                typeof(IEnumerable<>)
                    .MakeGenericType(property.Type.GetGenericArguments())
                    .IsAssignableFrom(property.Type))
            {
                var genType = property.Type.GenericTypeArguments.FirstOrDefault();
                if (genType != null)
                {
                    Expression subExp = Expression.Parameter(genType, "pEAN");
                    Expression subProp = Expression.PropertyOrField(subExp, member);    
                   
                    var expContains = Expression.Call(subProp, "Contains", null, constant);

                    var anyMethod = typeof(Enumerable).GetMethods().First(method => method.Name == "Any" && method.GetParameters().Length == 2).MakeGenericMethod(genType);

                    expression = Expression.Call(anyMethod, subProp, expContains);    
                }    
            }
            else
            {
                property = Expression.PropertyOrField(property, member);
            }
        }

        if (expression == null)
            expression = Expression.Call(property, "Contains", null, constant);

        var lambda = Expression.Lambda<Func<Product, bool>>(expression, parameterExpression);

        productsQuery = productsQuery.Where(lambda);
    }
}

productsQuery = productsQuery.OrderBy(p => p.Title);

var products = productsQuery.ToList().Select(p => (ProductDTO)p).ToList();

Everything in the if-part of if (property.Type... is me trying to get it to work. The DataModel looks like this:

public class Product
{
    public Guid Id {get;set;}
    public string Tile {get;set;}
    public List<ProductEAN> ProductEANs { get; set; }
}

public class ProductEAN
{
    public string EAN { get; set; }
    public decimal ProductCount { get; set; }
}


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source