3

Maybe this is a duplicate thread, but I am going to try, because there is a tiny difference.

I am trying to build a dynamic expression to filter a collection property.

The code:

public class TestEntity
{
    public int ID { get; set; }
    public string Name { get; set; }
    public IEnumerable<string> Values { get; set; }
} 

public class TestFilter
{
    public TestFilter()
    {
        var itens = new List<TestEntity>();

        itens.Add(new TestEntity { ID = 1, Name = "Test1", Values = new List<string> { "V1", "V2" } });
        itens.Add(new TestEntity { ID = 2, Name = "Test2", Values = new List<string> { "V6", "V3" } });
        itens.Add(new TestEntity { ID = 3, Name = "Test3", Values = new List<string> { "V4", "V5" } });
        itens.Add(new TestEntity { ID = 4, Name = "Test4", Values = new List<string> { "V2", "V3" } });

        itens = itens.Where(e => e.Values.Any(c => c.Equals("V2"))).ToList();

        **//Result IDs: 1, 4**
    }
}

The filter above will give me IDs 1 and 4 as result.

I want to filter entities where exists a certain value in the collection "Values".

So far, I have tried this thread, but didnt realize how it can be done.

Any help would be apreciated.

Community
  • 1
  • 1
  • So you want to make the expression in `c=> c.Equals("V2")` dynamic right? – ckruczek Jul 21 '16 at 12:41
  • I want to make e => e.Values.Any(c => c.Equals("V2")). Thank you! – marcodotnet Jul 21 '16 at 12:50
  • What do you expect in result? – Mohammad Akbari Jul 21 '16 at 17:06
  • Please provide the method signature (arguments, return type) you are looking for. – Ivan Stoev Jul 21 '16 at 17:31
  • Ivan, I want to build a dynamic expression like this one: e => e.Values.Any(c => c.Equals("V2")). For better understanding, here is the fiddle example: https://dotnetfiddle.net/wgETgq – marcodotnet Jul 21 '16 at 18:27
  • You don't get the point. Dynamically means you have something that is dynamic - property name, value list etc. From your examples it's not clear what is the dynamic part and how it is defined. This is the information that I was (and still) asking you. – Ivan Stoev Jul 21 '16 at 19:55
  • Dynamic property, in this case, is "Values". Dynamic value list: "V2". e => e.Property.Any(c => StringValueProp.Equals(dynamicValue)) – marcodotnet Jul 22 '16 at 13:24

1 Answers1

5

So you are seeking for a method which given a collection property name and value will produce Where predicate like e => e.Collection.Any(c => c == value).

You can use the following extension method (hope the code is self explanatory):

public static class QueryableExtensions
{
    public static IQueryable<T> WhereAnyEquals<T>(this IQueryable<T> source, string collectionName, object value)
    {
        var e = Expression.Parameter(typeof(T), "e");
        var collection = Expression.PropertyOrField(e, collectionName);
        var itemType = (collection.Type.IsIEnumerableT() ? collection.Type :
            collection.Type.GetInterfaces().Single(IsIEnumerableT))
            .GetGenericArguments()[0];
        var c = Expression.Parameter(itemType, "c");
        var itemPredicate = Expression.Lambda(
            Expression.Equal(c, Expression.Constant(value)),
            c);
        var callAny = Expression.Call(
            typeof(Enumerable), "Any", new Type[] { itemType },
            collection, itemPredicate);
        var predicate = Expression.Lambda<Func<T, bool>>(callAny, e);
        return source.Where(predicate);
    }

    private static bool IsIEnumerableT(this Type type)
    {
        return type.IsInterface && type.IsConstructedGenericType &&
            type.GetGenericTypeDefinition() == typeof(IEnumerable<>);
    }
}

like this:

itens = itens.AsQueryable().WhereAnyEquals("Values", "V2").ToList();

If you step through the code, the variable predicate contains the expression you are asking for.

Ivan Stoev
  • 195,425
  • 15
  • 312
  • 343