2010-08-09 4 views
5

Ich habe eine Abfrage, die überall wiederverwendet werden muss, und ich muss variieren, welche Eigenschaft/Spalte für einen Join verwendet wird.Verwenden eines Memberzugriffs-Lambda-Ausdrucks zum Parametrisieren eines LINQ to SQL-Prädikats

Was würde Ich mag zu können, ist zu tun, so etwas wie:

query = RestrictByProp(query, x=>x.ID); 

Ein extrem vereinfachte RestrictByProp() könnte *:

private static IQueryable<Role> RestrictByProp(IQueryable<Role> query, 
               Func<Role, int> selector) 
{ 
    return query.Where(x => selector(x) == 1); 
} 

Das Problem ist, dass selbst diese einfache Implementierung verursacht ein Laufzeitausnahme:

Method 'System.Object DynamicInvoke(System.Object[])' has no 
supported translation to SQL. 

** (Hier bin ich einfach nur mit einem einfachen ‚wo‘ Klausel - in meinem realen Code würde ich das Lambda zu holen verwenden, welche Eigenschaft für einen Join verwenden) *

Ich finde das seltsam, denn wenn das Mitglied Zugang Lambda erfolgt inline es ist in Ordnung:

private static IQueryable<Role> RestrictByID(IQueryable<Role> query) 
{ 
    return query.Where(x=> x.ID == 1); 
} 
.

LINQ to SQL ist auch glücklich, wenn Sie in einem Expression<Func<Role, bool>> übergeben (dh wenn der Parameter x=>x.ID == 1 ist, aber das Objekt besiegt, weil ich den Wert des rechten Operanden innerhalb der Abfrage bestimmen muss.

Gibt es eine Möglichkeit, den Lambda-Ausdruck in RestrictByProp() irgendwie zu munge, so dass LINQ to SQL SQL generiert?

Antwort

6

Zuerst müssen Sie Ihre Methodensignatur ändern:

private static IQueryable<Role> RestrictByProp(IQueryable<Role> query, 
    Expression<Func<Role, int>> selector) 

Das Ihre Lambda-Ausdruck bedeuten wird in einen Ausdrucksbaum umgewandelt anstelle eines Delegierten.

Sie müssen dann eine Expression<Func<Role, bool>> aus der vorhandenen Ausdrucksbaumstruktur erstellen.

Es sieht etwas wie folgt aus:

LambdaExpression lambda = (LambdaExpression) selector; 
var predicate = Expression.Equal(selector, Expression.Constant(1)); 
var lambdaPredicate = Expression.Lambda<Func<Role, bool>>(predicate, 
                  lambda.Parameters); 
return query.Where(lambdaPredicate); 
+0

Dank. Ich versuche das jetzt auf meine Bestie anzuwenden. Ich nehme an, ich muss einen riesigen Ausdrucksbaum aufbauen. Oder ist ExpressionVisitor hier praktisch? Für alle anderen, die diesen Code verwenden müssen, musste ich etwas ändern, damit es funktioniert (und ich kann nicht bearbeiten :): 1) Expression.Equal (Lambda *. Body * ... und 2) Expression.Lambda > – stucampbell

+0

@stucampbell: Danke, ich habe die Tippfehler behoben. Nicht sicher über ExpressionVisitor - ich habe es selbst noch nicht benutzt. –

+0

Hallo Jon, kannst du mit Erklärungen zu dieser Lösung tiefer gehen? Danke –

Verwandte Themen