Creando Relaciones de Base de Datos con Room en Android

5 minuto(s)

En un proyecto con Base de Datos las relaciones son parte importante del proceso de consulta y gestión de los datos, en Android mediante Room, específicamente  desde la versión Room 2.2.0 podemos apoyarnos sobre todas las posibles relaciones entre tablas como relación de uno a uno (one to one), uno a muchos (one to many) y muchos a muchos (many to many) usando la anotación @Relation, en este Post te mostraré como funciona.

Antes de continuar con este Post te invito a escuchar el Podcast: “Que Hacer Cuando Estamos En Casa”:

Spotify:

Sound Cloud:

Bien ahora continuemos con el Post: Creando Relaciones de Base de Datos con Room en Android.

Relaciones de uno a uno (One to one)

Supongamos que una persona solo puede tener un gato y un gato solo puede tener un dueño, esta es una relación uno a uno (one to one). Si queremos modelar esto en una base de datos relacional, creamos 2 tablas una llamada Gato y otra llamada Propietario, donde la tabla Gato tiene una referencia al id del propietario o la tabla Propietario tiene una referencia al id del gato. En Room creamos 2 entidades:


Ahora imaginemos que queremos mostrar la lista de todos los gatos y sus propietarios, para hacer esto podemos crear una clase de datos llamada GatoYPropietario:


Si quieres consultar lo anterior pero en SQLite, necesitaríamos ejecutar primero 2 consultas: una que obtenga todos los propietarios y otra que obtenga todos los gatos en función de los ids del propietario y luego manejar la asignación de objetos.


Para obtener una List<GatoYPropietario> usando Room, no necesitamos implementar las 2 consultas nosotros mismos y manejar el mapeo de objetos, sino usar la anotación @Relation.

En el ejemplo, dado que Gato tiene la información del propietario, agregamos la anotación @Relation a la variable gato especificando que la columna  propietarioid en la entidad Propietario corresponde a gatoPropietarioId:


Nuestro GatoYPropietario ahora se ha simplificado así:


Puedes ver que he agregado la anotación @Transaction, esto es para que Room ejecute las 2 consultas por nosotros de manera automática.

Relaciones de uno a muchos (One to many)

Ahora supongamos que un propietario puede tener varios gatos, aquí tendríamos una relación de uno a muchos entre las tablas Gato y Propietario. El esquema de la base de datos que definimos anteriormente no cambia, todavía mantenemos las mismas tablas, y la key que relaciona a ambas tablas, se puede utilizar, solo creamos la relación en el código.

Para mostrar la lista de propietarios con sus gatos, vamos a tener que crear una nueva clase de datos para modelar esto:


Para evitar tener que ejecutar 2 consultas separadas, podemos definir una relación de uno a muchos entre Gato y Propietario, al anotar el List<Gato> con la anotación @Relation como lo hicimos anteriormente:


El anterior GatoYPropietario se convierte en:

Relaciones de muchos a muchos (Many to many)

Para este caso imagina un mundo extraños en donde un propietario, puede tener varios gatos y que un gato puede tener múltiples propietarios. Para modelar este esquema, nuestras tablas Gato y Propietario no son suficientes. Dado que un gato puede tener múltiples propietarios, necesitamos tener múltiples entradas del mismo id del gato, que coincidan con diferentes ids de propietarios.

Debido a que gatoId es la key principal de la tabla Gato, no podemos insertar varios gatos con el mismo id. Para esto, necesitamos crear una tabla asociativa (también conocida como tabla de referencia cruzada) que mantenga los pares: ( gatoId, propietarioId):


Entonces si queremos obtener la lista de todos los propietarios con gatos List<PropietarioConGatos> usando solo consultas SQLite, necesitamos escribir 2 consultas, una que obtenga todos los propietarios y otra consulta que haga uso de la tabla Gato con la tabla asociada GatoPropietarioReferenciaCruzada por ejemplo:


Para implementar la consulta anterior en Room, necesitamos actualizar nuestra clase de datos PropietarioConGatos e indicarle a Room que para obtener la tabla Gatos, debe usar la tabla asociada GatoPropietarioReferenciaCruzada. Hacemos referencia a la tabla mediante el uso de Junction:


En nuestro PropietarioConGatos debemos seleccionar entre propietarios y devolver la clase de datos correcta:

Casos de uso de relación avanzada

Al usar la anotación @Relation, Room infiere la entidad a usar del tipo de la propiedad anotada por defecto. Por ejemplo , hasta ahora hemos visto una lista List<Gato> con @Relation, diciéndole a Room cómo modelar la clase y que columnas consultar.

Si queremos devolver un objeto diferente, por ejemplo una Mascota, que no es una entidad pero contiene algunos de los campos que necesitamos, podemos especificar la entidad que se utilizará en la anotación @Relation:


Si queremos devolver solo columnas específicas de una entidad, debemos indicarle a Room cuáles son, definiéndolas en la propiedad de proyección de @Relation.

Por ejemplo, supongamos que solo queremos obtener los nombres de todos los gatos en nuestra clase de datos PropietarioConGatos. Ya que necesitaríamos un List<String>, Room no puede deducir si esos Strings corresponden al nombre o la raza, por lo que debemos especificar la columna en la proyección:


Por si deseas crear una relación más estricta entre gatoPropietarioId y propietarioId, independientemente del tipo de relación que estés creando, usa una restricción Foreign Key entre los campos. Ten en cuenta que las keys externas de SQLite definen indices y pueden tener desencadenantes en cascada que actualicen o eliminen registros en las tablas de la base de datos, por ende debes decidir si deseas usar keys externas en función de si deseas este tipo de funcionalidad en tu base de datos.

Conclusión

En este Post puedes ver que usando Room, podemos crear relaciones de bases de datos de manera más dinámica y práctica en nuestros proyectos con Android.

Conforme practiques los conceptos expuestos, dominarás más esta forma de crear relaciones de base de datos.

Nota(s)

  • El código y lo métodos mostrados en este Post, pueden ser modificados, quedar obsoletos o continuar vigentes, esto no depende de mí, si no de los Desarrolladores que dan soporte a Android. 
  • No olvides que debemos usar la Tecnología para hacer cosas Buenas por el Mundo.

 

Síguenos en nuestras Redes Sociales para que no te pierdas nuestros próximos contenidos.