Durante la lettura di un articolo su Entity Framework performance, mi sono imbattuto in questo pezzo di informazioni:Riscrittura una query LINQ Expression per consentire la memorizzazione nella cache piano di esecuzione SQL
In secondo luogo, il problema [SQL Server non riutilizzare il piano di esecuzione ] si verifica in primo luogo perché (a causa di un dettaglio di implementazione) quando si passa un int ai metodi Skip() e Take(), Entity Framework non può vedere se sono stati passati valori assoluti come Take (100) o variabile come Take (resultsPerPage), quindi non sa se il valore deve essere parametrizzato.
La soluzione proposta è quella di cambiare questo stile di codice:
var schools = db.Schools
.OrderBy(s => s.PostalZipCode)
.Skip(model.Page * model.ResultsPerPage)
.Take(model.ResultsPerPage)
.ToList();
per questo stile:
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();
che permette Entity Framework di sapere che queste sono le variabili e che l'ha generato SQL dovrebbe essere parametrizzato, che a sua volta consente il riutilizzo del piano di esecuzione.
Abbiamo un codice nella nostra applicazione che utilizza le variabili allo stesso modo, ma è necessario creare l'espressione in fase di esecuzione poiché il tipo non è noto in anticipo.
Ecco che cosa ha usato per assomigliare:
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);
Il problema è che l'utilizzo Expression.Constant(convertedId)
provoca una costante da inserire dentro al SQL generato. Questo fa sì che l'SQL per cambiare per ogni nuovo articolo che stai osservando in su, che si ferma qualsiasi piano di esecuzione nella cache:
WHERE [Extent1].[Id] = 1234
e:
WHERE [Extent1].[Id] = 1235
e:
WHERE [Extent1].[Id] = 1236
La domanda allora, è Come si può utilizzare la costruzione di espressioni in modo tale da forzare la parametrizzazione dell'SQL generato? La sintassi () => convertedId
non funzionerà. Ho risposto a questo di seguito.
Non capisco, qual è la domanda qui? –
La domanda era come convertire il codice sopra per generare un SQL parametrizzato quando si utilizza Expression.Constant, poiché la sintassi '() => convertitoId' non funziona. –
Ho aggiornato il post principale per includere esplicitamente la domanda. –