这是迄今为止我最棘手的问题,我希望以前有人偶然发现了这个问题,并找到了一个优雅的答案。基本上,我有几个linq扩展方法(它们恰好在亚音速中,但适用于任何linq导数),它们完美地工作(扩展名为.WhereIn()和.WhereNotIn())。这些方法用于将linq转换为in()的sql等价物。现在下面的代码工作完全供给已知类型的参数(即,阵列或参数数组)时:现在对于复杂的部分LINQ扩展方法帮助寻求
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);
然而,:
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));
}
用法。我希望能够将一个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
jon - 我不能使用连接语法,因为代码是'提交'来在目前的表达式树和泛型中操作。然而,你的第三种选择可能会取得成果。我会在上面提到的上下文中仔细检查。所以是的,翻译成扩展方法的目标是 – 2010-08-05 09:00:19
@jim:“join”语法就等同于调用'Join'方法。我碰巧发现查询表达式中的连接比点符号更容易表达,但您可以将其表示为table1.Join(table2,x => x.Id,y => y.Id,(x,y)=> x)'没有任何问题。 – 2010-08-05 09:08:17
jon - 一个'最终游戏'会在上面使用你的想法,我能够这样做:var newJoin = query.Join(entity2,selector,selector2);但显然,这是不合法的语法等 – 2010-08-05 09:21:28