Base de datos de salas: experiencias de trabajar con varias tablas | de Eric N | enero 2023

En este artículo, exploraré tres métodos para consultar varias tablas a la vez, a saber, la consulta de varias tablas, el mapa múltiple y la clase de datos anotados en @Relation, y sus ventajas y desventajas con una aplicación de preguntas y respuestas de muestra. Primero mostraré cómo se consultan las respuestas a preguntas de texto libre, luego pasaré a un caso de uso más sofisticado: respuestas de opción múltiple. A partir de la versión 2.4.3 de Room, hay 3 métodos para consultar varias tablas de bases de datos al mismo tiempoventajas

  • Disponible desde la versión 1.1
  • Combina lógica/magia bajo el capó confiable y menos compleja
  • Simplemente

Desventajas

  • Clase de datos adicional requerida
  • La clase de datos extra puede ser grande si necesitamos muchas columnas

ventajas

  • Sin necesidad de clases adicionales
  • Aparentemente intuitivo

Desventajas

  • Relativamente nuevo desde Room 2.4.0
  • Un poco de lógica/magia de unión bajo el capó
  • No funciona para 3 o más mesas. ¡Investigaremos tales limitaciones en nuestra aplicación de muestra!

ventajas

  • Clases de datos adicionales requeridas
  • Cada clase es pequeña incluso si necesitamos muchas columnas (a diferencia de las consultas de tablas múltiples).

Desventajas

  • Disponible desde 1.0
  • De confianza
  • Funciona para 3 mesas o más.
  • Funciona para relaciones anidadas, pero tenga cuidado con el rendimiento
  • Un poco de lógica/magia de unión bajo el capó

¿Qué mejor manera de aprender haciendo? Para conocer los matices de las consultas de salas de varias mesas, usaremos una aplicación simple de preguntas y respuestas (Q&A). Nuestra aplicación de preguntas y respuestas admite preguntas basadas en texto y basadas en opciones. Un ejemplo de una pregunta basada en texto es «¿Cuál es tu comida favorita?». Un ejemplo de pregunta de opción múltiple es «Relaciones (¿prioridades?)» a la que el usuario puede responder «Comunicación», «Compasión», «Colaboración» y/o «Compromiso». Las estructuras de datos y sus relaciones son las siguientes:Comenzaremos con el caso de uso más simple, leyendo respuestas de texto de la base de datos de nuestra sala, y luego pasaremos a un caso de uso más sofisticado: respuestas de opción múltiple. El código fuente está en https://github.com/ericntd/myqa. La consulta de tabla múltiple encaja bien aquí debido a su simplicidad y al pequeño número de columnas que necesitamos. option_id = »»)fun readTextAnswers(): Flujo>Con la clase extra TextAnswerdata clase TextAnswer(pregunta val: Cadena,respuesta val: ¿Cadena?) Los resultados 🎊Código fuente: Mire la rama de preguntas basadas en texto. Por supuesto, podemos lograr los mismos resultados con Multi-Map y @Relation, pero esos enfoques serían demasiado complicados para nuestro caso de uso simple. Comencemos mostrando qué opciones puede seleccionar el usuario de cada pregunta. Y comencemos con el método más nuevo y aparentemente más intuitivo, Multi-map.@Query(«SELECCIONE * de la pregunta LEFT JOIN option ON question_id»)fun readMcqs(): Flujo> >No se requiere clase adicionalLos resultadosWow, todo parece ser un desastre. Tenga en cuenta que el texto en negrita está destinado a las preguntas como Relaciones, pero en cambio parecen ser las opciones disponibles para esas preguntas. Esto se debe a que Room Multi-Map actualmente no puede admitir tablas con los mismos nombres de columna. En nuestro caso, tanto las preguntas como la tabla de opciones tienen la misma clave principal «id». ¡La solución es hacer que los nombres de las columnas sean únicos! Una vez que cambiamos nuestras clases de datos a @Entity(tableName = «pregunta») clase de datos QuestionEntity(@PrimaryKey @ColumnInfo(name = «question_id») val id: String,@ColumnInfo(name = «question_text») val text: String) Y @Entity(tableName = «option») clase de datos OptionEntity(@PrimaryKey @ColumnInfo(name = «option_id») val id: String,@ColumnInfo(name = «question_id») val questionId: String,@ColumnInfo(name = » option_text «) val text: String,val humanId: String?) ¡Ahora funciona!Código fuente: consulte la rama de preguntas de opción múltiple-mapa múltiple-columnas fijas duplicadas Bajo el capó, el compilador Room genera un buen código de cursor antiguo que extrae los objetos Pregunta y Opción de los resultados de nuestra consulta SQL: @Overridepublic Flow< Mapa>> readMcqs() {cadena final _sql = «SELECCIONAR * de la pregunta INNER JOIN opción ON option.question_id = question.question_id»;final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 0);return CoroutinesRoom.createFlow(__db, false, nueva cadena[]{«pregunta»,»opción»}, nuevo invocable>>() {@Anular mapa público> call() arroja una excepción {Cursor final _cursor = DBUtil.query(__db, _statement, false, null);intenta {final int _cursorIndexOfId = CursorUtil.getColumnIndexOrThrow(_cursor, «question_id»);// otras columnas… Mapa final> _resultado = nuevo LinkedHashMap >();while (_cursor.moveToNext()) {// Pregunta y opción adicionales y poner en _result…}return _result;} final {_cursor.close();}}@Overrideprotected void finalize() {_statement .release( );}});} Noté que hay algunos índices de cursor extraños sin usar, como ningún problema de función real. Desafortunadamente, el mapa múltiple no parece admitir este tipo de uso en este momento. Espero que las futuras versiones de mapas múltiples admitan la consulta de 3 objetos relacionados. Intenté lo siguiente: @Query(«SELECCIONAR * DESDE (SELECCIONAR * de la pregunta INNER JOIN opción ON option.question_id = question.question_id) COMO q INNER JOIN respuesta ON answer.question_id = q.question_id»)fun readMcqAnswers2(): Flujo>, Lista>>Y Room no pudo generar código para cumplir con los requisitos:Error: No estoy seguro de cómo convertir un cursor al tipo de retorno de este método (kotlinx.coroutines.flow.Flow>, java.util.Lista>>).public abstract kotlinx.coroutines.flow.Flow>, java.util.Lista>> leerRespuestasMcq2(); Del mismo modo, Room no sabe cómo generar código para lo siguiente: @Query(«SELECT * FROM question» )fun readMcqAnswers5(): Flow>, Lista>>@Query(«SELECCIONE * DESDE la pregunta INNER JOIN (SELECCIONE * DESDE la opción INNER JOIN respuesta ON answer.option_id = opción .option_id) como ON a.question_id = question.question_id»)fun readMcqAnswers3(): Flujo>>@Query(«SELECCIONAR * DE la pregunta»)fun readMcqAnswers4(): Flujo>>Finalmente recurrí al método clásico de anotación @Relation y satisfizo nuestras necesidades aquí: // la clase Entitydata QuestionWithRelations(@Embeddedval question: QuestionEntity,@Relation(parentColumn = «question_id»,entityColumn = «question_id») opciones válidas: Lista,@Relation(parentColumn = «question_id»,entityColumn = «question_id»)vale Respuestas: Lista)// El DAO@Query(» SELECT * FROM question»)fun readMcqAnswers1(): Flujo>Código fuente: echa un vistazo a la rama de preguntas y respuestas de opción múltiple Debajo del capó, Room también genera un código que usa el viejo y buen cursor SQLite, pero me parece más legible en comparación con el código del mapa múltiple. No veo ninguna razón por la cual las iteraciones futuras de mapas múltiples no puedan coincidir con las funcionalidades de @Relation y @Embedded para 3 objetos. No está claro qué tan común es una solicitud de este tipo y dónde se ubica en la tabla de prioridades del equipo de desarrollo de Room. Si cada respuesta contiene una lista de identificadores de opciones, ¿sería la lógica más simple? Déjame saber lo que piensas en una respuesta. Las consultas SQL múltiples son más lentas que una sola consulta SQL ¡Las consultas SQL simultáneas no son necesariamente más rápidas que las consultas secuenciales! Como siempre, no hay una bala de plata. Debe elegir la herramienta que mejor se adapte a sus necesidades y limitaciones. En nuestra aplicación actualmente usamos los 3 métodos diferentes

  1. Consultas de varias tablas para preguntas y respuestas simples basadas en texto
  2. Mapa múltiple para 2 relaciones de objetos, por ejemplo, perfiles y fotos
  3. @Relation y @Embedded para 3 relaciones de objetos, por ejemplo, preguntas, opciones y respuestas

https://github.com/ericntd/myqaFelicitaciones a Christa Mabee por compartir la existencia de Room Multi-Map y su exploración. Gracias también por corregir este artículo.

Deja una respuesta

Tu dirección de correo electrónico no será publicada.