【问题标题】:Building a dynamic expression tree to filter on a collection property 2构建动态表达式树以过滤集合属性 2
【发布时间】:2016-11-25 01:24:22
【问题描述】:

也许这是一个重复的线程,但我会尝试,因为有一个微小的差异。

我正在尝试构建一个动态表达式来过滤集合属性。

代码:

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**
    }
}

上面的过滤器会给我 ID 1 和 4 作为结果。

我想过滤集合“Values”中存在某个值的实体。

到目前为止,我已经尝试过this线程,但没有意识到它是如何做到的。

我们将不胜感激。

【问题讨论】:

  • 所以你想让c=&gt; c.Equals("V2")中的表达式动态化对吧?
  • 我想制作 e => e.Values.Any(c => c.Equals("V2"))。谢谢!
  • 您对结果的期望是什么?
  • 请提供您要查找的方法签名(参数、返回类型)。
  • Ivan,我想构建一个像这样的动态表达式:e => e.Values.Any(c => c.Equals("V2"))。为了更好地理解,这里是小提琴的例子:dotnetfiddle.net/wgETgq

标签: c# entity-framework lambda filtering


【解决方案1】:

所以你正在寻找一种方法,它给定集合属性名称和值将产生Where 谓词,如e =&gt; e.Collection.Any(c =&gt; c == value)

您可以使用以下扩展方法(希望代码不言自明):

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<>);
    }
}

像这样:

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

如果您单步执行代码,变量predicate 包含您要求的表达式。

【讨论】:

  • 伊万,太美了!非常感谢!
猜你喜欢
  • 2012-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-07
相关资源
最近更新 更多