這是迄今爲止我最棘手的問題,我希望以前有人偶然發現了這個問題,並找到了一個優雅的答案。基本上,我有幾個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