IEnumerable<int>.contains(MemberExpression)的动态Linq表达式

6

我想使用Linq表达式树创建一个表达式来模拟这个:

List<int> ids = new List<int>();

// Fill ids with data

db.Where(a => ids.Contains(a.Id));

这是我目前的进展,但仍有所遗漏:
MemberExpression me = Expression.Property(pe, typeof(T).GetProperty(property));

Expression callContains = Expression.Call(typeof(System.Linq.Enumerable), "Contains", new Type[] { me.Type }, me);

我该如何正确地完成我想要做的事情?

我只有一个问题,为什么你想做这样的事情? - Ondrej Janacek
2
我正在使用linq构建一个非常大且非常复杂的搜索机制。我所拥有的框架不允许访问IQueryable对象,只能访问我们自定义的模型,因此我不能像通常那样链接可查询对象。相反,我根据所选的搜索选项逐个动态构建表达式。 - TheNerd
3个回答

15

因为Contains是一个扩展方法,所以您还需要将ids集合作为参数提供,这种情况下,作为ConstantExpression

您的实现可能略有不同,但它看起来会像这样:

public static IQueryable<T> DynamicContains<T, TProperty>(
    this IQueryable<T> query, 
    string property, 
    IEnumerable<TProperty> items)
{
    var pe = Expression.Parameter(typeof(T));
    var me = Expression.Property(pe, property);
    var ce = Expression.Constant(items); 
    var call = Expression.Call(typeof(Enumerable), "Contains", new[] { me.Type }, ce, me);
    var lambda = Expression.Lambda<Func<T, bool>>(call, pe);
    return query.Where(lambda);
}

db.DynamicContains("Id", ids);

我没有看到你的方法中任何地方使用了 property 参数,我认为你的意思是使用 typeof(T).GetProperty(property)(而不是 "Id")。 - King King
谢谢!这正是我所需要的,我现在明白了之前我所缺失的东西。 - TheNerd
2
为什么不使用Expression.Property这个重载,使你的第二行代码变成var me = Expression.Property(pe, property);呢? - Scott Chamberlain

0

作为对 @p-s-w-g 答案的补充,DynamicNotContains 是:

    public static IQueryable<T> DynamicNotContains<T, TProperty>(this IQueryable<T> query, string property, IEnumerable<TProperty> items)
    {        
        var pe = Expression.Parameter(typeof(T));
        var me = Expression.Property(pe, property);
        var ce = Expression.Constant(items);
        var call = Expression.Call(typeof(Enumerable), "Contains", new[] { me.Type }, ce, me);
        var lambda = Expression.Lambda<Func<T, bool>>(Expression.Not(call), pe);

        return query.Where(lambda);
    }
db.DynamicNotContains("Id", ids);

0
您可以添加对 Mono.CSharp dll 的引用,然后使用 Evaluator 类在运行时编译 C# 代码, 然后连接字符串以轻松创建 LINQ 查询, 最后编译它们 这不会很慢,而且很容易。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接