'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 |
|---|
