我正在使用實體框架版本4.我需要比較一個大型(〜一百萬條記錄)SQL Server表與從Web返回的較長(〜2000)複雜對象數組服務。需要比較五個不同的屬性,以確定複雜對象的實例是否已經在數據庫中。涉及複雜對象的實體框架的Linq表達式構建
我創建了一個函數,它返回在.Where和.Any方法中使用的表達式。它看起來像這樣(其中A是複雜對象,而tblA是EF類):
function Expression<tblA, bool> GetSearchPredicate(A a)
{
return ta => ta.Field1.Equals(a.Field1)
&& ta.Field2.Equals(a.Field2)
&& ta.Field3.Equals(a.Field3)
&& ta.Field4.Equals(a.Field4)
&& ta.Field5.Equals(a.Field5);
}
這可行。我可以通過這樣比較所有2000個A的實例:
IEnumerable<A> objects = [web service call];
var result = objects.Select(a => !db.tblA.Any(GetSearchPredicate(a)));
這也適用。但速度很慢。所以我研究了構建一種實用方法,該方法可以構建一個可以通過EF直接傳輸到數據庫的表達式。
我使用this question中的代碼作爲構建該實用方法的基礎。該問題中的示例顯示將單個屬性與一系列常量進行比較,而我的版本將不得不將多個屬性與多個常量進行比較。我盡力而爲低於:
public static IQueryable<TEntity> WhereIn<TEntity>
(
this ObjectQuery<TEntity> query,
IEnumerable<Expression<Func<TEntity, bool>>> predicates
)
{
if (predicates == null) throw new ArgumentNullException("predicates");
IEnumerable<ParameterExpression> p = predicates.Select(pred => pred.Parameters.Single()).ToArray();
IEnumerable<Expression> equals = predicates.Select(value =>
(Expression)value.Body);
Expression bigEqual = equals.Aggregate((accumulate, equal) =>
Expression.Or(accumulate, equal));
var result1 = Expression.Lambda<Func<TEntity, bool>>(bigEqual, p.First());
var result = query.Where(result1);
return result;
}
這將這樣被調用:
IEnumerable<A> objects = [web service call];
var result = db.tblA.WhereIn(objects.Select(a => GetSearchPredicate(a)));
我得到的是一個消息說,「TA」(即針對TEntity對象佔位符)未綁定。我認爲這是因爲我有多個表達式(變量predicates
)被合併,也許這個消息被拋出,因爲我只是從IEnumerable的第一個predicates
傳遞參數。但即使predicates
只有一個表達式,也會發生這種情況。
我有理由相信,基於該方法我聯繫,我可以建立這五個特性(通過A.Field5
的A.Field1
值)比較恆定的一種表現,而不是傳遞的參數predicates
已經讓他們組合成一系列的表達。但我寧願不要,因爲這需要我的方法知道它的類型爲A
和tblA
,這與泛型和通用目的相反。 (它也會很複雜和凌亂。)
我希望我展示的例子能解釋我想要做的事情。它能以通用的方式完成嗎?
在什麼時候,你得到的消息? –
@GregBair當我嘗試執行該函數的結果。對不起,我把那部分拿出來了! –
不要試圖無益,但使用可以導入到EF模型中的存儲過程來完成(並且速度非常快)會非常簡單。你有沒有特別的理由不這樣做? –