2014-01-06 50 views
0

我需要共享4-5個不同實體集合的謂詞,最好不要複製代碼。所有實體都實現了接口IEntity實體框架通用謂詞

private Expression<Func<T, bool>> GetUpdatedPredicate<T>(DateTime? lastUpdated) where T : IEntity { 
    if (lastUpdated.HasValue) { 
     return x => (
      x.CreatedAt >= lastUpdated || 
      (x.UpdatedAt.HasValue && x.UpdatedAt >= lastUpdated) 
     ); 
    } 

    return x => true; 
} 

然後像這樣使用,跨多個實體集:

(
    from s in Db.EntityA.Where(GetUpdatedPredicate<EntityA>(lastUpdated)) 
    where (
     s.User.Id == 1 
    ) 
    select s 
).Future(); 

但提供了錯誤: 無法轉換類型'EntityA爲鍵入 'IEntity'。 LINQ to Entities僅支持投射EDM基元或枚舉類型。有沒有辦法做到這一點,而不重複的代碼?

+0

我認爲你正在嘗試做類似於我正在嘗試做的事情,並遇到同樣的問題。我試圖按組織過濾,您正嘗試按用戶進行過濾。看看這裏的解決方案:http://stackoverflow.com/q/20052827/150342 – Colin

+0

這樣做的工作,但@ Moeri的解決方案......國際海事組織是更好的;) – Jamie

回答

3

實體框架有問題,與你的接口類型約束這裏:

where T : IEntity 

您需要添加T需要是一個類的附加約束:

where T : class, IEntity 

而且,如果你開始發現LINQ表達式,我可以強烈推薦LinqKit庫。它有一些非常非常漂亮的東西。

+0

你從字面上回答了問題,就像我完成了使用表達式生成器(即)'Expression.Parameter(.....)'。但你的回答是正確的。開始發現LINQ表達式?我被侮辱了;)但是我還沒有偶然發現LinqKit,所以謝謝:) – Jamie

+1

嘿嘿,我說「如果」:)我很早就遇到同樣的問題,而我自己發現了表情,因此我的假設。 LinqKit順便說一句,你應該可以通過使用LinqKit提供的.Invoke()和.Expand()模式來避免大部分手動表達式構建。 – Moeri

+1

+1。我也強烈推薦linqkit,並且在很多其他情況下都不適合的情況下使用了predicatebuilder。對此不能說很多好東西。哦,還有,當然好的答案:-)'如果' –

0

我正在提出一種替代方法。

第一,而不必返回一個表達的方法,你將不得不像一個私人靜態方法:

private static bool Evaluate(IEntity x, DateTime? lastUpdated) { 
    if (lastUpdated.HasValue) { 
     return x.CreatedAt >= lastUpdated || 
      (x.UpdatedAt.HasValue && x.UpdatedAt >= lastUpdated) 
     ); 
    } 

    return true; 
} 

很明顯,你可以更好的名字提。然後使用它像:

var result = Db.EntityA.Where(i => i.Evaluate(i, lastUpdated)); 
+2

EF仍然將無法將包含.net方法的表達式轉換爲sql。 – Maarten

0

EF現在嘗試包括調用你的方法到生成的表達,這是行不通的。您必須從表達式中排除方法調用。

嘗試在定義查詢之前從您的方法創建表達式(不,我沒有測試過)。

DateTime lastUpdated = ...; 
var updatedPredicate = GetUpdatedPredicate<EntityA>(lastUpdated); 
var query = 
(
    from s in Db.EntityA.Where(updatedPredicate) 
    where (
     s.User.Id == 1 
    ) 
    select s 
).Future(); 
+0

不幸的是,這有相同的結果:S – Jamie

+0

與@ Moeri的答案,你仍然可以使用.Where(GetUpdatedPredicate (lastUpdated)):) – Jamie