2015-10-06 31 views
1

實體框架的解決辦法查詢我有一個類T:基於原語的組合,內存

class T { 
    int Prop1Id; 
    int Prop2Id; 
} 

在運行時,在內存中,我有:

var L1 = new List<T>(); 

和L1包含下面的T對象:

Prop1 Prop2 
12  5 
6  7 
8  9 
10  12 

不能做到以下幾點:

attributes.Where(x=>L1.Any(y=>y.Prop1ID == x.Prop1ID && y.Prop2ID == x.Prop2ID)) 

attributes是EF型(即:在DB)

這不工作,因爲它不能創建T的恆定值類型 - 預計只有原語和可枚舉。

有沒有人想出了一個解決辦法,而不是回收所有的屬性,以便它們在內存中的IEnumerable而不是IQueryable?對我來說,這不是真正:-(

回答

2

一個選項假設你提供了什麼,2個屬性是整數類型。所以,你可以試試這個變通,我們需要您的列表轉換成另一種字符串鍵列表如下:

var stringKeys = L1.Select(e => e.Prop1 + "_" + e.Prop2); 
//then use stringKeys normally 
attributes.Where(x=> stringKeys.Contains(x.Prop1ID + "_" + x.Prop2ID)); 

如果不是這種情況(不限於整數性能),我們可能有基於列表L1打造的具備條件做更復雜的方式:

var result = attributes; 
foreach(var e in L1){ 
    var k1 = e.Prop1; 
    var k2 = e.Prop2; 
    var sub = attributes.Where(x => k1 == x.Prop1ID && k2 == x.Prop2ID);  
    result = result.Concat(sub); 
} 
//then access result instead of attributes 

上述方法可能效率稍差。它將在連接(UNION ALL)所有結果之前針對數據庫表執行L1.CountWHERE。不過我相信,如果它在關鍵列上執行,性能仍然不錯。

最後溶液是嘗試使用表達式樹(表示Where通過了謂詞):

//suppose your attributes is a set of Attribute 
var p = Expression.Parameter(typeof(Attribute)); 
var p1 = Expression.Property(p, "Prop1ID"); 
var p2 = Expression.Property(p, "Prop2ID"); 
var initBool = Expression.Constant(false) as Expression; 
//build the BodyExpression for the predicate 
var body = L1.Aggregate(initBool, (c,e) => { 
       var ep1 = Expression.Constant(e.Prop1); 
       var ep2 = Expression.Constant(e.Prop2); 
       var and = Expression.And(Expression.Equal(ep1, p1), Expression.Equal(ep2,p2)); 
       return Expression.Or(c, and); 
      }); 
attributes.Where(Expression.Lambda<Func<Attribute, bool>>(body, p)); 

注意的x.Prop1ID類型應的L1.Prop1每個元素的類型完全匹配(如既要intfloat,...)。相同的條件適用於所有相應的屬性。否則,您需要修改代碼來構建表達式樹(這裏的原因是Expression.Equal要求2個操作數表達式具有相同的數據類型)。我沒有使用表達式樹來測試最後一個代碼,但這個想法非常明確。

涉及Expression(內部)的最後一個選項是嘗試使用LinqKit。我甚至沒有使用過這個庫,但它可以幫助您在很多情況下免費構建Expression樹。因此,如果它可以幫助您運行原始查詢而不會遇到您提到的異常,請嘗試一下。