[C# Talk] : Query re-use in Linq To SQL
Har du også overvejet om mulighederne for query re-use i Linq To SQL? Det vil sige det at man kan genbruge dele af sine Linq To SQL queries, ved at laegge dem ud som properties i sine
datamodel-klasser.
Det er noget man normalt ikke kan i Linq fordi hvis du laver en custom
property, og vil bruge den i en select statement, saa kan Linq ikke
finde ud af at lave den til en expression som kan omsaettes til SQL.
Men jeg har fundet en maade at goere det paa alligevel! Der er vist et
par andre gutter paa nettet der ogsaa har gjort det, men jeg synes
alligevel det var meget sjovt at lave min egen implementering.
Her er et simpelt eksempel. Lad os sige du har en entity class (fx en
klasse som er autogenereret af SQLMetal), vi kan jo kalde den Project.
Den har bla. to properties der hedder Income og Expenses. Lad os sige du
tit laver queries op mod den klasse hvor du gerne vil have Overskuddet
(revenue). Revenue er defineret som Income minus Expenses. Det var nu
oplagt at tilfoeje en ekstra property til Project klassen, saaledes:
public partial class Project
{
public double Revenue
{
get { return Income - Expenses; }
}
}
Denne property kan godt bruges til fx at populere felterne i en gridview
med, EFTER du har eksekveret din query, men du kan IKKE bruge den
direkte i queryen. Fx kan du ikke skrive:
var ds = from p in myDataContext.projects where p.Revenue > 0 select p;
Det vil komme ud med en fejlmeddelelse om at propertyen Revenue ikke har
nogen SQL-implementation.
Til redning kommer min nye extension method kaldet DynamicWhere. Hvis du
skifter Where ud med DynamicWhere, og skriver din Revenue property en
lille smule op, kan det lade sig goere.
Tricket er, at du skal lade Revenue levere en Expression<Func<>> tilbage
i stedet for et resultat. Men for at queryen skal kunne acceptere
at du skriver fx p.Revenue > xxx saa skal Revenue jo vaere en property
der leverer en double. I stedet laver du saa en statisk skygge-funktion
med et andet navn som leverer en Expression tilbage. Den funktion
associerer du saa med din Revenue funktion via en attribute. Saadan her:
[DynamicProperty(ExpressionPropertyName = "RevenueExpr")]
public double Revenue
{
get { return RevenueExpr.Compile().Invoke(this); }
}
public static Expression<Func<Project, double>> RevenueExpr
{
get { return (p => p.Income - p.Expenses); }
}
Jeg har ladet Revenue genbruge den associerede funktion saaledes at man
ikke bliver noed til at skrive p.Income - p.Expenses to gange.
Klik her for at downloade DynamicWhere som DLL projekt.
