Sentencias en LINQ (VI): Ordenación


Otra de las funcionalidades básicas de cualquier consulta es la ordenación de los datos. Por norma nos bastará con dos criterios: campo por el que filtrar y orden en el que filtrar (ascendente o descendente).

La cláusula LINQ para realizar el filtrado es orderby. Si no se añade ningún parámetro de orden, los campos se recuperarán por defecto de forma ascendente. En caso de querer un orden descendente, añadiremos la palabra reservada descending a continuación del campo por el que queremos ordenar. La palabra reservada ascending fuerza a que la ordenación sea, en todo caso, ascendente.


            var consulta = from cliente in DataLists.ListaClientes
                           orderby cliente.Nombre ascending
                           select cliente;

            foreach (var cliente in consulta)
            {
                Console.WriteLine(string.Format("ID: {0}\tNOMBRE: {1}\tF.NACIMIENTO: {2}",
                    cliente.Id, cliente.Nombre, cliente.FechaNac));
            }

En este caso, los registros se ordenan por orden alfabético por el campo nombre, siempre de menor a mayor.

En el caso contrario (descending) el campo de ordenación es el mismo, pero en orden descendente (de mayor a menor).


            var consulta = from cliente in DataLists.ListaClientes
                           orderby cliente.Nombre descending
                           select cliente;

            foreach (var cliente in consulta)
            {
                Console.WriteLine(string.Format("ID: {0}\tNOMBRE: {1}\tF.NACIMIENTO: {2}",
                    cliente.Id, cliente.Nombre, cliente.FechaNac));
            }

Ordenación y expresiones lambda

Al igual que con otros métodos, LINQ permite la utilización de extensiones para permitir el uso expresiones lambda. Los métodos para este menester son OrderBy y OrderByDescending. Las consultas equivalentes a las anteriores serían las siguientes:


            var consultaAsc = DataLists.ListaClientes.OrderBy(cliente => cliente.Nombre);
            var consultaDesc = DataLists.ListaClientes.OrderByDescending(cliente => cliente.Nombre);

Además, es posible invertir el orden en el que una lista está construida mediante el método Reverse().


            var consulta = (from cliente in DataLists.ListaClientes
                           orderby cliente.Nombre descending
                           select cliente).Reverse();

            foreach (var cliente in consulta)
            {
                Console.WriteLine(string.Format("ID: {0}\tNOMBRE: {1}\tF.NACIMIENTO: {2}",
                    cliente.Id, cliente.Nombre, cliente.FechaNac));
            }

Como podemos observar, el resultado es el mismo que utilizar ascending en lugar de usar descending.

Ordenación multiple

Es también posible indicar un suborden dentro de un orden. Por ejemplo, imaginemos que queremos ordenar todas las líneas de pedido por ID del pedido. Si obtenemos (por ejemplo) cinco registros cuyo ID de pedido es “1”, puede que nos interese añadir un nuevo campo de ordenación para crear un orden dentro del orden. Por ejemplo, por el ID del producto. Si es lo que deseamos, podemos hacerlo separando los campos de ordenación a través de una coma:


            var consulta = from linea in DataLists.ListaLineasPedido
                            orderby linea.IdPedido, linea.IdProducto
                            select linea;

El resultado muestra cómo los registros se ordenan primero por el campo IdPedido y, a continuación, por IdProducto.

Pero… ¿y si quisiéramos que la lista se ordenara de forma descendente por el ID de pedido y a continuación de forma ascendente por el Id de producto? No hay problema. Es posible utilizar los calificadores ascending y descending junto al campo que califican, de la siguiente forma:


            var consulta = from linea in DataLists.ListaLineasPedido
                            orderby linea.IdPedido descending, linea.IdProducto ascending
                            select linea;

Nuevamente, el resultado nos muestra que los pedidos se ordenan del 12 al 1, mientras que los productos, dentro del orden anterior, se ordenan de menor a mayor.

El equivalente con expresiones lambda a estas dos funciones sería el siguiente:


            var consultaAscAsc = DataLists.ListaLineasPedido.OrderBy(linea => linea.IdPedido).OrderBy(linea => linea.IdProducto);
            var consultaDescAsc = DataLists.ListaLineasPedido.OrderByDescending(linea => linea.IdPedido).OrderBy(linea => linea.IdProducto);

Ordenación y paginación

En el artículo en el que hablamos de los métodos de particionado hablamos acerca de la paginación de una consulta. A la hora de particionar con el objetivo de paginar una consulta, hay que tener especial cuidado con el orden en el que se aplican ambas operaciones: la ordenación siempre se ejecutará antes de la partición.

Siempre hay que realizar en primer lugar la operación de ordenación. A continuación, se paginará (particionará) sobre esa consulta. Así, la siguiente paginación a la que se le ha aplicado un criterio de ordenación sería correcta:


            int tamPagina = 5;
            int paginaActual = 2;
            var consultaPaginada = (from producto in DataLists.ListaProductos
                                    orderby producto.Descripcion
                                    select producto).Skip((paginaActual - 1) * tamPagina).Take(tamPagina);

Vemos el resultado:

En cambio, si realizásemos primero la partición y después la ordenación, lo que estaríamos logrando sería recuperar n registros sin ordenar que, una vez recuperados, serían ordenados. Veamos qué ocurriría si invirtiésemos el orden de la consulta anterior:


            int tamPagina = 5;
            int paginaActual = 2;
            var consultaPaginada = (from producto in DataLists.ListaProductos
                                    select producto).
                                    Skip((paginaActual - 1) * tamPagina).
                                    Take(tamPagina).
                                    OrderBy(prod => prod.Descripcion);

Lo cual sería claramente incorrecto, ya que se aplicaría la ordenación sobre el fragmento de información que acabamos de recuperar:

Con esto finalizamos las operaciones de ordenación en LINQ. Mañana echaremos un vistazo a otra de las características de LINQ: operaciones sobre conjuntos.

Anuncios

One comment

  1. Cuando indicas la manera de ordenar por varias propiedades mediante lambda, diría que no es la forma correcta, ya que OrderBy ordena elementos de una secuencia. Por tanto los segundos OrderBy reordenarán la secuencia que devuelva el primer OrderBy.

    La manera correcta de ordenar una secuencia por dos propiedades sería utilizar primero OrderBy(Descending) y después ThenBy(Descending) de esta manera no se chafará la ordenación anterior.

    var consultaAscAsc = DataLists.ListaLineasPedido.OrderBy(linea => linea.IdPedido).ThenBy(linea => linea.IdProducto);

    var consultaDescDesc = DataLists.ListaLineasPedido.OrderByDescending(linea => linea.IdPedido).ThenByDescending(linea => linea.IdProducto);

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