Czytając artykuł o Entity Framework performance, natknąłem się na ten kawałek informacji:Przepisywanie kwerendy LINQ Expression włączyć buforowanie SQL Execution Plan
Po drugie, problem [SQL Server nie będzie ponowne wykonanie planu ] występuje przede wszystkim dlatego, że (ze względu na szczegóły implementacji) podczas przekazywania int do metod Pomiń() i Take(), Entity Framework nie może zobaczyć, czy zostały przekazane bezwzględne wartości, takie jak Take (100) lub zmienna jak Take (resultsPerPage), więc nie wie, czy wartość powinna być sparametryzowana.
Proponowane rozwiązanie jest zmienić ten styl kodu:
var schools = db.Schools
.OrderBy(s => s.PostalZipCode)
.Skip(model.Page * model.ResultsPerPage)
.Take(model.ResultsPerPage)
.ToList();
na tym stylu:
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();
który pozwala Entity Framework wiedzieć, że są one zmienne i że wygenerowany SQL powinien zostać sparametryzowany, co z kolei pozwala na ponowne wykorzystanie planu wykonania.
Mamy pewien kod w naszej aplikacji, który używa zmiennych w ten sam sposób, ale musimy budować wyrażenie w czasie wykonywania, ponieważ typ nie jest znany z góry.
Oto co kiedyś wyglądać tak:
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);
Problem polega na tym, że za pomocą Expression.Constant(convertedId)
powoduje stałą być włożona do wygenerowanego SQL. To powoduje, że SQL zmienić dla każdego nowego elementu spojrzeć w górę, który zatrzymuje żadnego planu wykonania buforowanie:
WHERE [Extent1].[Id] = 1234
oraz:
WHERE [Extent1].[Id] = 1235
oraz:
WHERE [Extent1].[Id] = 1236
Powstaje zatem pytanie, to jest Jak używać budowania wyrażeń w taki sposób, aby wymusić parametryzację wygenerowanego kodu SQL? Składnia () => convertedId
nie będzie działać. Odpowiedziałem na to poniżej.
Nie rozumiem, o co tu chodzi? –
Pytanie dotyczyło sposobu konwersji powyższego kodu w celu wygenerowania sparametryzowanego SQL podczas korzystania z Expression.Constant, ponieważ składnia '() => convertId' nie działa. –
Zaktualizowałem główny post, aby jednoznacznie uwzględnić to pytanie. –