2010-08-09 7 views
5

Tengo una consulta que debe reutilizarse por todas partes y necesito variar qué propiedad/columna se usa para una unión.Uso de una expresión lambda de acceso de miembro para parametrizar un predicado LINQ to SQL

Lo que me gustaría ser capaz de hacer es algo como:

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

Un extremadamente simplificada RestrictByProp() podría ser *:

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

El problema es que incluso esta simple aplicación provoca una Excepción de tiempo de ejecución:

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

** (Aquí solo agrego un simple 'donde' cláusula - en mi código real que estaría utilizando el lambda para recoger la propiedad que se utiliza para una combinación) *

Me parece extraño, porque si el acceso de los miembros de lambda se realiza en línea, está muy bien:

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

LINQ to SQL también es feliz si pasa un Expression<Func<Role, bool>> (es decir, cuando el parámetro es x=>x.ID == 1) pero eso derrota al objeto porque necesito que el valor del operando de la mano derecha sea determinado dentro de la consulta.

¿Hay alguna manera de resolver de alguna manera la expresión lambda en RestrictByProp() para que LINQ to SQL sepa cómo generar el SQL?

Respuesta

6

En primer lugar, tiene que cambiar su método de firma:

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

que significará su expresión lambda se convierte en un árbol de expresión en lugar de un delegado.

A continuación, deberá compilar un Expression<Func<Role, bool>> desde el árbol de expresiones existente.

Se verá algo así:

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

Gracias. Estoy tratando de aplicar eso a mi bestia de una consulta ahora. Supongo que tendré que construir un árbol de expresiones masivas. ¿O es aquí donde ExpressionVisitor es útil? Para cualquier otra persona que necesite usar este código, tuve que cambiar algo para que funcione (y no puedo editar :): 1) Expression.Equal (lambda * .Body * ... and 2) Expression.Lambda > – stucampbell

+0

@stucampbell: Gracias, he corregido los errores tipográficos. No estoy seguro acerca de 'ExpressionVisitor' - Todavía no lo he usado. –

+0

Hola Jon, ¿puedes profundizar con explicaciones sobre esta solución? Gracias –

Cuestiones relacionadas