2017-09-06 96 views
4

所以我厭倦了一遍又一遍重寫相同的查詢。用IsInDateTimeRange擴展IQueryable

repo.Query().Where(stuff => stuff.Timestamp >= minTime && stuff.Timestamp <= maxTime && ...); 

我想我應該有一個名爲IsInDateTimeRange方法但是延長IQueryable,並使用它像這樣

repo.Query().IsInDateTimeRange(stuff => stuff.Timestamp, minTime, maxTime) ... 

這將是IEnumerable非常方便,只需一個Func<T, DateTime>和兩個DateTime S,爲IQueryable我需要採取Expression,我不確定如何使用它。

這是我的嘗試,但似乎沒有工作。

public static IQueryable<TValue> IsInDateTimeRange<TValue>(
     this IQueryable<TValue> self, 
     Expression<Func<TValue, DateTime>> getMember, 
     DateTime minTime, 
     DateTime maxTime) 
    { 
     return self.Where(value => minTime >= getMember(value) && maxTime <= getMember(value)); 
    } 
+1

當你說沒有工作,請解釋這是什麼意思。例外?編譯錯誤? –

+1

由於'getMember(value)'噪聲,大多數Linq提供者將無法將轉換後的表達式轉換爲商店查詢。您必須使用常規的'Expression.Property'訪問器手動替換相關部分。 – haim770

+0

是的,編譯器錯誤。由於它不是委託,因此無法調用getMember。 – jool

回答

7

您可以通過手動構建基於傳遞給該方法的屬性訪問表達式表達式實現這一點:

public static IQueryable<TValue> IsInDateTimeRange<TValue>(
    this IQueryable<TValue> self, 
    Expression<Func<TValue, DateTime>> getMember, 
    DateTime minTime, 
    DateTime maxTime) 
{ 
    var getMemberBody = getMember.Body; 
    var filter = Expression.Lambda<Func<TValue, bool>>(
     Expression.And(
      Expression.LessThanOrEqual(
       Expression.Constant(minTime), 
       getMemberBody 
      ), 
      Expression.LessThanOrEqual(
       getMemberBody, 
       Expression.Constant(maxTime) 
      ) 
     ), 
     getMember.Parameters 
    ); 
    return self.Where(filter); 
} 
+0

打敗我吧。只是我可能做的調整就是你實際上不需要使用getMember.Parameters.First()。您應該能夠將'getMembers.Parameters'作爲第二個參數傳遞給'Lambda <>()'。另外,第一個'LessThanOrEqual'應該是'GreaterThanOrEqual' :)。 –

+0

@MikeStrobel你是對的,編輯使它如此:) –

+0

修復你的小邏輯錯誤(你使用了兩次'<=')。 –