Ho alcune espressioni che generano codice da passare come l'istruzione "where" in un database letto, e sto cercando di accelerare un po 'le cose.Modifica del valore di un'espressione costante in un'espressione binaria preesistente
Questo esempio sotto fa una cui dichiarazione per abbinare il PK di un tavolo con un passato di valore:
private Expression MakeWhereForPK(int id)
{
var paramExp = Expression.Parameter(typeof(Brand),"b");
//Expression to get value from the entity
var leftExp = Expression.Property(paramExp,"ID");
//Expression to state the value to match (from the passed in variable)
var rightExp = Expression.Constant(id,typeof(int));
//Expression to compare the two
var whereExp = Expression.Equal(leftExp,rightExp);
return Expression.Lambda<Func<Brand,bool>>(whereExp,paramExp);
}
Quanto sopra
è una semplificazione per la domanda - la cosa reale include il codice per prendere il tavolo per interrogare su e trovare il suo PK ecc e 'efficace facendo la stessa cosa come si potrebbe fare nel codice di solito:
ctx.Brands.Where(b => b.ID = id);
Questo funziona bene, ma, mentre si fa a test per ottimizzare le cose un po' ho trovato la sua piuttosto lento - fare il precedente 1000000 richiede circa 25 secondi. È meglio se ometto l'ultima riga sopra (ma ovviamente è inutile!), Quindi sembra che Expression.Lamba stia prendendo circa i 2/3 del tempo, ma il resto non è eccezionale.
Se tutte le query dovessero accadere contemporaneamente, potrei trasformarle in un'espressione di stile IN
e generare una volta, ma sfortunatamente non è possibile, quindi quello che spero è di risparmiare su gran parte della generazione di cui sopra, e riusare semplicemente l'espressione generata, ma passando un diverso valore di id
.
Si noti che, poiché questo verrà passato a Linq, non posso compilare l'espressione per avere un parametro intero che posso passare in invocazione - deve rimanere come albero delle espressioni.
Quindi la seguente potrebbe essere una versione semplice ai fini di fare l'esercizio tempistica:
Expression<Func<Brand,bool>> savedExp;
private Expression MakeWhereForPKWithCache(int id)
{
if (savedExp == null)
{
savedExp = MakeWhereForPK(id);
}
else
{
var body = (BinaryExpression)savedExp.Body;
var rightExp = (ConstantExpression)body.Right;
//At this point, value is readonly, so is there some otherway to "inject" id,
//and save on compilation?
rightExp.Value = id;
}
return savedExp;
}
Come potrei riutilizzare l'espressione, solo con un diverso valore di id?
sarebbe un 'idea di usare un [ 'ParameterExpression'] (http://msdn.microsoft.com/en-us/library/system.linq.expressions.parameterexpression.aspx) invece di un' ConstantExpression'? (A proposito, se le prestazioni sono un problema, perché usare LINQ affatto? LINQ scambia le prestazioni per non dover imparare SQL.) – Andomar
@Andomar: il secondo 'ParameterExpression' renderà' Func '. Non può essere usato come un predicato per 'Where'. –
Dennis