Hacer un buscador sencillo con Linq dinámico

Pongámonos en contexto. Estoy rehaciendo la página de FinderCar, porque estamos consiguiendo visitantes pero no conseguimos materializar ninguna compra.

Es lo lógico y lo esperado. Y para conseguir el objetivo sigo extrictamente un proceso de evolución basado en hipótesis y en cambiar el rumbo cada vez que sea necesario, tenga las consideraciones técnicas que tenga por detrás.

Por eso estoy rehaciendo la interfaz, y requiero de un ligero buscador que, cuanto más términos introduzca, más restringa el conjunto de resultados.

Y para ello necesito que mi Linq sea dinámico.

El infierno de Linq dynamic

La verdad es que me las esperaba más sencillas. Me he puesto a buscar por stack overflow a ver cual era la solución más práctica… y me ha costado un mundo encontrarla.

He probado la librería Dynamic Linq, he probado hacer un horrendo switch, y así me he tirado casi un día entero sin conseguir algo tan sencillo como las siguientes reglas:

  • Si introduzco “Peug” me devuelve todos los vehículos con la marca Peugeot.
  • Si introduzco “Peug 208” me devuelve todos los vehículos de la marca Peugeot y el modelo 208 (restringiendo cada vez más los resultados).
  • Si introduzco un número, lo considera el coste máximo que estoy buscando y me restringe el listado por ese precio.

La verdad es que andaba bastante desesperado; cuando he encontrado (de refilón) una referencia a una clase llamada PredicateBuilder, y allí que me he lanzado a buscarla.

Y luego de unas cuantas pruebas, ahora sí que sí, veo que si que me vale y me facilita mucho el tema. Y eso que aún estoy en proceso y afinamiento con el tema del precio.

Showing the code

Lo primero es bajarme e instalar de Nuget el paquete de LinqKit  y luego revisar su el ejemplo de su web,  que me viene como anillo al dedo.

Al final mi método ha quedado así:

Public class List<VehiculoEntity> Busca(string searchText)
{
    var palabras = searchText.Trim().Split(' ');
    ListadoVehiculos = model.GetAllVehiculos().ToList();

    var predicate = PredicateBuilder.New<VehiculoEntity>();
    foreach (var termino in palabras)
    {
        predicate = predicate.And(p => p.Marca.Contains(termino)
                                    || p.Modelo.Contains(termino));

        var prueba = int.TryParse(termino, out int numero);
        if (prueba)
        {predicate = predicate.Or(p => p.PrecioFinderCar <= numero);}
    }
}

Es decir, separo los términos de búsqueda por los espacios, y lanzo un bucle para cada término. Dentro construyo el Where y se lo añado a los Where anteriores con un And.

Es decir algo así:

Where (Marca.Contains(termino1) or Modelo.Contains(termino1)) AND (Marca.Contains(termino2) or Modelo.Contains(termino2))

Y luego, si lo que viene es un número, le meto un OR que me restringe a los que tengan el valor igual o inferior al campo PrecioFindercar.

Y funciona!!

A partir de aquí, espero que sea tan útil para otros como lo es para mí.

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s