2010-08-09 10 views
5

Mam kwerendę, która musi zostać ponownie użyta w każdym miejscu i muszę zmienić, która właściwość/kolumna zostanie użyta do łączenia.Używanie wyrażenia lambda dostępu do elementu do parametryzowania LINQ do predykatu SQL

Co chciałbym być w stanie zrobić coś takiego jak:

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

skrajnie uproszczony RestrictByProp() może być *:

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

Problemem jest to, że nawet ta prosta realizacja powoduje wyjątek w czasie wykonywania:

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

** (Tutaj dodaję proste słowo "gdzie" klauzula - moim prawdziwym kodzie byłbym za pomocą lambda odebrać którym nieruchomość użyć do złączenia) *

Uważam to dziwne, bo jeśli lambda dostęp członek odbywa inline jest w porządku:

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

LINQ do SQL jest również szczęśliwy, jeśli przejdziesz w Expression<Func<Role, bool>> (tj. gdy parametr to x=>x.ID == 1), ale to pokonuje obiekt, ponieważ potrzebuję wartości prawostronnego argumentu do ustalenia w zapytaniu.

Czy istnieje sposób, aby w jakiś sposób munge wyrażenie lambda w RestrictByProp(), tak aby LINQ do SQL wie, jak wygenerować SQL?

Odpowiedz

6

Po pierwsze, trzeba zmienić metodę Twój podpis:

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

To będzie oznaczać swoje wyrażenia lambda przekształca się w drzewie wyrażenie zamiast delegata.

Następnie należy zbudować Expression<Func<Role, bool>> z istniejącego drzewa wyrażeń.

To będzie wyglądać coś takiego:

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

Dzięki. Próbuję teraz zastosować to do mojej bestii zapytania. Przypuszczam, że będę musiał zbudować ogromne drzewo ekspresji. A może przydaje się ExpressionVisitor? Dla każdego, kto potrzebuje użyć tego kodu, musiałem zmienić coś, aby działało (i nie mogę edytować :): 1) Wyrażenie.Equal (lambda * .Body * ... i 2) Expression.Lambda > – stucampbell

+0

@stucampbell: Dzięki, poprawiłem literówki. Nie jestem pewien co do wyrażenia "ExpressionVisitor" - jeszcze go nie używałem. –

+0

Cześć Jon, czy możesz pogłębić wyjaśnienia dotyczące tego rozwiązania? Dziękuję –

Powiązane problemy