Continuamos con el proyecto crear una API Web en ASP.NET. En cualquier API que tenga base de datos surge la necesidad de seleccionar cierta información haciendo consultas muy concretas. Para ello nosotros hemos utilizado tres mecanismos que os vamos a introducir en el artículo de hoy: LINQ, Lambda Expressions y DTO.
En este proyecto vamos a tener que realizar consultas a la base de datos muy específicas. Por ejemplo las medidas obtenidas por un dispositivo con un nombre concreto ó las medidas obtenidas de un dispositivo en un periodo de tiempo. Para ello, vamos a usar LINQ (Language-INtegrated Query) y Lambda Expressions, en combinación con el uso de DTO (Data Transfer Object) y así poder enviar al cliente solo la información que realmente necesita.
¿Qué es LINQ?
LINQ es un conjunto de herramientas que permite realizar todo tipo de consultas a distintas fuentes de datos, como pueden ser objetos, bases de datos, XML, etc. Estas herramientas definen varios tipos de funciones que unifican las operaciones más comunes con datos, de esta manera permite utilizar el mismo lenguaje para cualquier transacción necesaria con datos. La sintaxis es similar a la existente en SQL, a continuación os mostramos un ejemplo de una consulta utilizando LINQ:
Código
¿Por qué usar expresiones Lambda?
Además se pueden utilizar expresiones Lambda en combinación con LINQ lo que hace posible acceder a las funciones que ofrece LINQ como si fueran métodos de los objetos. Esto quiere decir que se podrán utilizar las funciones para realización de consultas de datos que ofrece LINQ (select, join, where, etc.) directamente desde los objetos. La sintaxis de las Expresiones Lambda se encuentra definida en la siguiente guía web de programación C# de Microsoft:
¿Para qué usar DTO?
Por último, será necesario utilizar DTO para tratar la información resultante de las expresiones Lambda. Se denomina DTO a aquellas clases que representan un subconjunto de otra clase del modelo o una combinación de varias de ellas. En este desarrollo se ha utilizado por dos motivos:
- Es necesario utilizarlo para la realización de consultas a la base de datos usando Lambda Expressions y LINQ.
- En ciertas ocasiones no se desea que se el usuario reciba toda la información del modelo de datos para la consulta que realiza y se utiliza DTO para limitar la información que recibirá.
Para tratar la respuesta de una consulta como un DTO se necesita primero definir el mapeo de atributos de la clase del modelo de datos con la clase DTO definida.
Implementación de consultas usando DTO, LINQ y Lambda Expressions
En nuestra API hemos necesitado crear nuevas clases de modelo que representen las nuevas tablas de la base de datos, así como controladores para servir la información de estos modelos. Esto es algo que ya comentamos cómo hacer en el artículo ASP.Net, como crear una API Web.
Solo nos gustaría recalcar que en caso de que necesitéis hacer algo similar necesitaréis añadir una nueva migración y actualizar la base de datos. Para esta segunda fase del proyecto hemos generado un nuevo archivo pero está vez le llamaremos por ejemplo, Second, añadiendo así una nueva migración y a continuación ejecutándola.
Vamos a dejar a un lado la teoría y pasamos a la práctica. Para implementar estas consultas necesitamos codificar principalmente tres partes:
- Las clases DTO.
- El mapeo de las clases del modelo a nuestro DTO.
- Las consultas a la base de datos en función de la petición del cliente.
Creación de clases DTO
Primero creamos una carpeta nueva con el nombre DTOs y creamos cada clase DTO con los atributos que queramos devolver al cliente de la API Rest.
En la siguiente imagen mostramos el aspecto que tiene una clase DTO. No tiene ningún misterio en cuanto a código se refiere, es más entender el concepto de que cada una de estas clases representa datos que se mandarán al usuario.
Código
Mapeo de clases de modelo a DTO
Una vez creadas las clases DTO, tenemos que añadir en las clases controladoras el código que se encargará de hacer el mapeo de los atributos de la clase del modelo de datos con la clase DTO definida.
En el código se puede apreciar cómo hemos hecho el mapeo del objeto Measure a MeasureDto. No tiene complejidad más allá de acceder correctamente a los datos, como es el caso de Device.name, que pertenece a la clase Device utilizada por Measure.
Código
Consultas a base de datos
En nuestro caso hemos implementado varias consultas a base de datos en los controladores, ya que de momento nuestros servicios no tienen lógica. En caso de tener una cierta complejidad en vuestra API, deberíais valorar el lugar donde situar estas consultas.
Las consultas que hacemos utilizan los datos introducidos por el cliente para filtrar los datos de la base de datos y de esta manera devolver un resultado más acotado. Además cruzamos datos de varias tablas para devolver una respuesta más completa.
Os mostramos algunos ejemplos de consultas a la base de datos usando LINQ, Lambda Expressions y DTO usadas en las nuevas funciones GET.
En el primer caso se aprecia cómo se busca en la tabla de dispositivos los que tengan el homeId introducido por parámetro, siendo estos dispositivos devueltos al cliente.
Código
En este segundo ejemplo la búsqueda se hace a través del deviceName y lo que devolveremos al cliente son las averías del dispositivo con ese nombre. Para devolver las averías a partir de dispositivos y averías hacemos uso de AsBreakdownDto, una de las funciones de mapeo que explicamos en el apartado anterior.
Código
Pruebas
Podéis realizar pruebas usando el cliente Postman. Tenemos un artículo explicando qué es, qué funcionalidades ofrece, una puesta en marcha y un primer ejemplo.
Hemos hecho algunas pruebas para verificar que los nuevos métodos funcionan correctamente. Para ello lo primero que hacemos(y que no mostramos porque no aporta demasiado) es insertar datos en la base de datos a través de los métodos POST implementados.
Una vez tenemos datos guardados ya podemos hacer alguna petición a los servicios de consulta.
Conclusiones
Como veis con estos tres conceptos podemos hacer virguerias en cualquier proyecto de forma muy sencilla y además bastante limpia. ¡Ahora os toca ponerlo en práctica! Recordad que tenéis el repositorio en GitHub con todo el código actualizado y, como siempre, los Pull Request, comentarios y sugerencias serán bien recibidos 🙂 . Además para que podáis ver todo lo nuevo que hemos incluído en esta segunda parte os dejamos el enlace al commit.
Por último, os adelantamos que para la siguiente entrega de este proyecto veremos cómo restringir el acceso a los usuarios usando individual account y token based authorization.
Esperamos que os haya parecido interesante y que os sea de ayuda 🙂 .