Consulta de la entidad con LINQ usando el nombre del campo Dyanmic

c# dynamic-linq expression-trees lambda linq-to-entities

Pregunta

He creado una pantalla de búsqueda dinámica en ASP.NET MVC. Recuperé los nombres de los campos de la entidad a través de la reflexión para que el usuario pudiera elegir en qué campos quería buscar en lugar de mostrar todos los campos en la vista.

Cuando el resultado de la búsqueda se publica de nuevo en el controlador, recibo un objeto FormCollection que contiene el FieldName y el valor. No sé en qué campos se están buscando, y FormCollection solo contiene campos que fueron seleccionados por el usuario.

Quiero poder ahora tomar ese nombre de campo y aplicarlo a mi declaración LINQ cuando pregunto en la base de datos, por ejemplo:

public List<People> SearchPeople(Dictionary<string, string> fieldValueDictionary)
{
    List<People> searchResults = new List<People>();

    foreach (string key in fieldValueDictionary.Keys)
    {
         searchResults.Add(entities.People.Where(p => p.<use the key string as the fieldName> == fieldValueDictionary[key]));
    }

    return searchResults;
}

Donde tengo "usar la cadena de clave como el nombre de campo" sería como p => p.FirstName == fieldValueDictionary [clave] donde clave = "Nombre". He intentado y no he podido utilizar los árboles de expresión de Lambda, y he tenido un poco de éxito con Dynamic LINQ. La otra alternativa es hacer algo como:

public List<People> SearchPeople(Dictionary<string, string> fieldValueDictionary)
{
    IQueryable<People> results = entities.People;

    foreach (string key in fieldValueDictionary.Keys)
    {
         switch (k)
         {
             case "FirstName": results = results.Where(entities.People.Where(p => p.FirstName == k);
             case "LastName": results = results.Where(entities.People.Where(p => p.LastName == k);
             // Repeat for all 26 fields in table
         }
    }

    return results.ToList<People>();
}

ACTUALIZACIÓN : He investigado en los árboles de expresión Lambda a través de las siguientes publicaciones:

crear dinámicamente expresiones lambdas + linq + OrderByDescending

Problema de parámetro con Expression.Lambda ()

LINQ: pasar la expresión lambda como parámetro para ser ejecutado y devuelto por el método

He llegado tan lejos como para obtener un lambda para mostrar lo siguiente: "p => p.FirstName", pero no puedo hacer que esto funcione en un dónde. ¿Alguna sugerencia? Mi código está abajo:

MemberInfo member = typeof(People).GetProperty("FirstName");
ParameterExpression cParam = Expression.Parameter(typeof(People), "p");    
Expression body = Expression.MakeMemberAccess(cParam, member);        

var lambda = Expression.Lambda(body, cParam);

Respuesta aceptada

Después de muchas más pruebas, errores y búsquedas, encontré accidentalmente otra publicación SO que cubre el mismo problema:

InvalidOperationException: ningún método 'Where' en el tipo 'System.Linq.Queryable' es compatible con los argumentos proporcionados

Aquí está mi código modificado que funciona:

        IQueryable query = entities.People;
        Type[] exprArgTypes = { query.ElementType };

        string propToWhere = "FirstName";            

        ParameterExpression p = Expression.Parameter(typeof(People), "p");
        MemberExpression member = Expression.PropertyOrField(p, propToWhere);
        LambdaExpression lambda = Expression.Lambda<Func<People, bool>>(Expression.Equal(member, Expression.Constant("Scott")), p);                            

        MethodCallExpression methodCall = Expression.Call(typeof(Queryable), "Where", exprArgTypes, query.Expression, lambda);

        IQueryable q = query.Provider.CreateQuery(methodCall);

Con algunas modificaciones bastante fáciles, espero poder hacer que esto funcione con cualquier tipo.

Gracias de nuevo por sus respuestas Ani y John Bowen


Respuesta popular

¿Has intentado obtener el valor de PropertyInfo?

entities.People.Where(p => (p.GetType().GetProperty(key).GetValue(p, null) as string) == fieldValueDictionary[key])


Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow