在閱讀上Entity Framework performance的文章時,我看到這條信息傳來:重寫LINQ查詢表達式來啓用緩存SQL執行計劃
其次,問題[SQL Server將不能重複使用的執行計劃]首先發生,因爲在將一個int傳遞給Skip()和Take()方法時(因爲實現細節),Entity Framework無法查看它們是否傳遞了像Take(100)這樣的絕對值,或者像Take(resultsPerPage)這樣的變量,所以它不知道值是否應該被參數化。
所提出的解決辦法是改變這種風格的代碼:
var schools = db.Schools
.OrderBy(s => s.PostalZipCode)
.Skip(model.Page * model.ResultsPerPage)
.Take(model.ResultsPerPage)
.ToList();
在這種風格:
int resultsToSkip = model.Page * model.ResultsPerPage;
var schools = db.Schools
.OrderBy(s => s.PostalZipCode)
.Skip(() => resultsToSkip) //must pre-calculate this value
.Take(() => model.ResultsPerPage)
.ToList();
這使得實體框架知道這些變量的產生SQL應該參數化,這又可以使執行計劃被重用。
我們在我們的應用程序中有一些代碼以相同的方式使用變量,但是我們必須在運行時構建Expression,因爲類型事先並不知道。
這裏是它曾經的樣子:
var convertedId = typeof(T).GetConvertedIdValue(id);
var prop = GetIdProperty(typeof(T));
var itemParameter = Expression.Parameter(typeof(T), "item");
var whereExpression = Expression.Lambda<Func<T, bool>>
(
Expression.Equal(
Expression.Property(
itemParameter,
prop.Name
),
Expression.Constant(convertedId)
),
new[] { itemParameter }
);
return Get<T>().Where(whereExpression);
的問題是,使用Expression.Constant(convertedId)
導致常數來生成的SQL插入。這將導致SQL來改變你看看每一個新項目,這將停止任何執行計劃緩存:
WHERE [Extent1].[Id] = 1234
和:
WHERE [Extent1].[Id] = 1235
和:
WHERE [Extent1].[Id] = 1236
那麼問題,是如何使用Expression Building來強制生成SQL的參數化?() => convertedId
語法不起作用。我在下面回答了這個問題。
我不明白,這裏有什麼問題? –
問題是如何將上面的代碼轉換爲使用Expression.Constant時生成參數化SQL,因爲'()=> convertedId'語法不起作用。 –
我已更新主帖以明確包含該問題。 –