LINQ扩展方法有助于寻求

时间:2010-08-05 08:47:49

标签: c# .net linq subsonic

这是迄今为止我最棘手的问题,我希望有人之前偶然发现了这个问题,并找到了一个优雅的答案。基本上,我有一些linq扩展方法(恰好是亚音速,但适用于任何linq衍生物),它们完美地工作(扩展为.WhereIn()和.WhereNotIn())。这些方法用于将linq转换为in()的sql等价物。现在,当提供已知的类型参数(即数组或参数数组)时,下面的代码可以正常工作:

public static IQueryable<T> WhereIn<T, TValue>(
    this IQueryable<T> query, 
    Expression<Func<T, TValue>> selector, 
    params TValue[] collection) where T : class
{
    if (selector == null) throw new ArgumentNullException("selector");
    if (collection == null) throw new ArgumentNullException("collection");
    ParameterExpression p = selector.Parameters.Single();

    if (!collection.Any()) return query;

    IEnumerable<Expression> equals = collection.Select(value =>
       (Expression)Expression.Equal(selector.Body,
            Expression.Constant(value, typeof(TValue))));

    Expression body = equals.Aggregate(Expression.Or);

    return query.Where(Expression.Lambda<Func<T, bool>>(body, p));
}

用法:

var args = new [] { 1, 2, 3 };
var bookings = _repository.Find(r => r.id > 0).WhereIn(x => x.BookingTypeID, args);
// OR we could just as easily plug args in as 1,2,3 as it's defined as params
var bookings2 = _repository.Find(r => r.id > 0).WhereIn(x => x.BookingTypeID, 1,2,3,90);

然而,现在对于复杂的部分。我希望能够将IQueryable对象传递给上面的重载版本,该版本接受第二个linq对象作为参数,以实现相当于select * from table1 where table1.id in(select id from table2)。这是方法签名,实际编译好,但缺少所有重要的逻辑:

public static IQueryable<T> WhereIn<T, TValue, T2, TValue2>(
    this IQueryable<T> query, 
    Expression<Func<T, TValue>> selector, 
    T2 entity2, 
    Expression<Func<T2, TValue2>> selector2) where T : class
{
    if (selector == null) throw new ArgumentNullException("selector");
    if (selector2 == null) throw new ArgumentNullException("selector2");
    ParameterExpression p = selector.Parameters.Single();
    ParameterExpression p2 = selector2.Parameters.Single();

    /* this is the missing section */

    /* i'd like to see the final select generated as 
     *
     * select * from T where T.selector in(select T2.selector2 from T2)
     */


    return  null; 
    // this is just to allow it to compile - proper return value pending
}

用法:

var bookings = _repository.Find(r => r.BookingID>0)
                .WhereIn(x => x.BookingTypeID, new BookingType(), y => y.BookingTypeID);
我在这里咆哮着一个不存在的(表达式)树:-) - 或者这是非常可行的。

一切顺利 - 这是希望。

jim

2 个答案:

答案 0 :(得分:4)

为什么不只是使用加入?

var query = from x in table1
            join y in table2 on x.Id equals y.Id
            select x;

或者,如果每个y可能有多个x值:

var query = from x in table1
            join z in table2.Select(y => y.Id).Distinct() on x.Id equals z
            select x;

我希望这样的查询能够在SQL数据库中得到很好的优化。

或者如果你真的想使用Where

var query = table1.Where(x => table2.Select(y => y.Id).Contains(x.Id));

我可能会遗漏更大的东西......或者可能是将上述查询翻译成扩展方法就是您正在寻找的东西:)

答案 1 :(得分:-1)

我最终选择了一种扩展方法来实现这一目标,但仍然不是100%成功。

一旦我将其与所有其他选项集成在一起,我将在稍后删除实际的完整工作代码。