miércoles, 26 de febrero de 2014

Linq, recuperar número de filas y hallar la media en un join

Como tantas veces, estoy apasionado con una refactorización de código que me obliga a intentar ganar tiempo con Entity Framework, abandonado guarrerías de foreach y construyendo querys en Linq más complejas.

Así tengo un negocio que tiene a su vez unos productos asignados. Lo que quiero es crear un objeto negocio que me incluya el número de productos que tiene y la media de la puntuación que han recibido todos.

resultado = (from negocio negocio in db.negocios
                  
where negocio.Id == pNegocio.Id

                   join negociositem item in db.negociositems
                   on negocio.Id equals item.business_id into items
                                

                  select new negocioconrating
                                
{
                                     Id = negocio.Id,
                                     logo = negocio.logo,
                                     name = negocio.name,

                                     numrating = items.Count(),
                                     mediarating = items.Average(p => p.rating),
                                    
                                 }).ToList<
negocioconrating>();

¿Que está ocurriendo aquí?

Las primeras dos líneas son para seleccionar un negocio específico por medio de un parámetro llamado pNegocio que incluye un campo Id.

A continuación hago un join (internamente un inner join) con la tabla negociositems para recuperar aquellos item que tengan el campo business_id igual al id del item seleccionado. Es importante que este resultado (el del join) lo almacene en una variable temporal llamada items, porque esto es lo que me permitirá realizar operaciones sobre el listado completo.

Ahora hago un select sobre un nuevo objeto, en donde voy a almacenar los datos recuperados; así las primeras lineas son normales, cargando los resultados en las propiedades de la clase.

Lo interesante son las dos últimas líneas del select. En la primera hago un Count() diréctamente y recupero el número de item que he recuperado. La segunda línea utiliza el método Average que soporta los objetos IEnumerable, y le paso una lambda como función; en la cual escojo el campo del cual quiero obtener la media.

Una vez realizado parece sencillo, pero me ha tocado bucear un rato para encontrar estas dos soluciones.

Espero que sea de ayuda.

1 comentario:

jmservera dijo...

Me encanta LINQ para estas cosas. Si no necesitas una lista y sólo necesitas enumerar es mejor no hacer un ToList y dejar el resultado tal cual, así, si por ejemplo devuelves el resultado por WebAPI/Rest se convierte directamente en una query REST que podrías filtrar y ejecutar el filtro en el SQL directamente desde una llamada REST.