Buscar en la BD
El objetivo de la búsqueda es filtrar los registros que se ven para que aparezcan solamente los libros cuyos campos de texto relevantes contengan una cadena que coincida con la cadena de búsqueda. Si la cadena de búsqueda aparece en un campo de un registro Authors, en vez de en un registro Books, lo que aparece son todos los libros de ese autor.
La imagen siguiente muestra los resultados de una búsqueda del término «dark». La búsqueda encuentra dos libros. En ambos casos la cadena de búsqueda aparece en el campo Title del libro.
Búsqueda local y búsqueda en BD
Puede realizar una búsqueda local desde su dispositivo móvil en los datos descargados de la BD o puede buscar directamente en la BD en el servidor. Cada método tiene sus ventajas, como explicamos a continuación.
•Si realiza una búsqueda local primero debe cargar todos los registros de la BD en la memoria. Este método es más rápido que buscar directamente en la BD, pero consume más memoria al tener que cargar todos los registros en la memoria, sobre todo si se trata de un gran volumen de datos.
•Si la búsqueda consiste en enviar una solicitud SQL a la BD, el tiempo que tardan las transacciones de BD es mayor. Sin embargo, se consume menos memoria de almacenamiento de datos porque solamente se devuelven los registros de la búsqueda.
Puede sopesar las ventajas de cada uno de los métodos para decidir cuál le conviene más en cada caso.
Mecanismo
Es posible usar distintos métodos para realizar búsquedas. El que hemos usado aquí combina una búsqueda SQL de BD con un enfoque específico de una instancia local de MobileTogether; lo explicamos a grandes rasgos a continuación.
1.La cadena de búsqueda se introduce en un campo de edición.
2.El campo de edición está asociado con el nodo SearchText de la fuente de página $PERSISTENT, por lo que el texto de la búsqueda pasa automáticamente a este nodo al introducir el texto de la búsqueda en el campo de edición (véase el nodo resaltado en la imagen anterior).
3.Al hacer clic en el botón Buscar se ejecutan dos acciones, una tras otra: (i) la fuente de página $BookCatalog se vuelve a cargar con solamente los registros Authors que contienen la cadena de búsqueda en los datos del autor o de alguno de sus libros (ver punto 4 más abajo); (ii) una acción Eliminar nodo(s) que elimina los libros de ese autor que no contienen la cadena de búsqueda en ninguno de sus campos, lo que deja solamente los libros de ese autor que sí la contienen (punto 5 más abajo).
4.Al volver a cargar la fuente de página se desencadena la búsqueda en la BD de la cadena de búsqueda mediante una instrucción SQL. Como resultado, un la fuente de página $BookCatalog se volverá a cargar pero solo los autores relevantes (si la cadena aparece en los datos del autor o al menos en los de uno de sus libros). Para más información consulte el apartado Búsqueda SQL en la BD.
5.Como la búsqueda SQL devuelve a los autores con todos sus libros, los libros en los que no aparece la cadena de búsqueda se eliminan. Para más información consulte Eliminar libros que no coinciden.
La cadena de búsqueda
Creamos un campo de edición en el que el usuario pueda introducir la cadena de búsqueda. Asociamos el campo de edición con el nodo $PERSISTENT/Root/SearchText (arrastrando y soltando el nodo en el campo de edición). Ahora el texto de la búsqueda se almacena en este nodo, al que se puede acceder más tarde para las acciones.
El botón Buscar
La búsqueda empieza cuando se hace clic en el botón Buscar. Las acciones del evento AlHacerClic (imagen siguiente) son (i) una acción Volver a cargar de la fuente de página $BookCatalog y (ii) una acción Eliminar nodo(s). A continuación describimos ambas acciones con más detalle. Por el momento es importante saber que la acción Volver a cargar de la fuente de página $BookCatalog inicia la búsqueda en la BD. Consulte la sección siguiente, Búsqueda SQL en la BD. Puede encontrar la descripción de la acción Eliminar nodo(s) en la sección Eliminar libros que no coinciden, más abajo.
Búsqueda SQL en la BD
Cuando se desencadena la acción Volver a cargar para $BookCatalog, una instrucción SQL () selecciona las filas de la tabla Authors que tienen algún campo que contenga el texto de la búsqueda (en el registro Authors o en alguno de los registros Books relacionados). Para ello siga estos pasos:
Configuración de la fuente de página $BookCatalog
La fuente de página $BookCatalog se configuró originalmente para que seleccione todos los registros de la tabla Authors, donde cada registro Authors contiene a su vez registros secundarios relacionados Books. Ahora vamos a añadir una cláusula WHERE a la instrucción SQL para filtrar los registros Author para que seleccionen solamente los registros que coincidan con la búsqueda. Como la cláusula WHERE tiene que construirse con una expresión XPath compleja, usaremos una función para implementar la expresión XPath. La función se llama DBSQLSearch(), como se puede ver en la imagen siguiente. En la imagen puede ver la instrucción SQL en el panel inferior de la ventana. En esta instrucción SQL la cláusula WHERE es el valor de retorno de la función DBSQLSearch().
Nota: | Para editar o ver la configuración de la fuente de página $BookCatalaog, haga clic en el icono Configuración de $BookCatalaog en el panel Fuentes de página. |
Funciones de búsqueda
Para realizar la búsqueda vamos a crear dos funciones: DBSQLSearch() y DBFieldsSearch(). Para acceder al cuadro de diálogo Funciones XPath que ve en la imagen siguiente use el comando de menú Proyecto | Funciones XPath/XQuery.
declare function DBSQLSearch() { let $search-text := $PERSISTENT/Root/SearchText return if ($search-text != '' ) then DBFieldsSearch( 'Authors', $search-text ) || ' OR Author_ID IN (SELECT AuthorID FROM Books WHERE ' || DBFieldsSearch( 'Books', $search-text ) || ')' else '' }
|
declare function DBFieldsSearch($table-name, $search-text) { string-join($SearchFields($table-name) ! ( . || ' LIKE ''%' || $search-text || '%''' ), ' OR ' ) }
|
map { 'Authors' : ('AuthorName', 'Website', 'Country'), 'Books' : ('Title', 'ISBN', 'Publisher', 'Year', 'Genre', 'Price') }
|
La función DBSQLSearch() hace lo siguiente:
•Si el texto de búsqueda no es una cadena vacía, la instrucción SELECT se construye usando la función DBFieldsSearch() dos veces: la primera para buscar en los campos de la tabla Authors y la segunda para buscar en los campos de la tabla Books.
•La función DBFieldsSearch() construye la cláusula WHERE para buscar en las tablas (Authors y Books) haciendo referencia a la asignación $SearchFields de las columnas de la tabla de BD. La asignación $SearchFields se almacena como una variables definidas por el usuario a la que se accede desde el comando de menú Proyecto | Variables globales.
•Como se define en la función DBSQLSearch(), si el texto de búsqueda es una cadena vacía, la cláusula WHERE de la instrucción SQL $BookCatalog será una cadena vacía (véase la función DBSQLSearch() más arriba). En este caso, la instrucción SQL no tiene una cláusula WHERE y se devuelven todos los registros Authors.
La estructura de la instrucción SELECT creada si la cadena de búsqueda no está vacía sería la siguiente:
SELECT <AuthorsFields-1 to AuthorsFields-Z> FROM "Authors"
WHERE AF1 LIKE '%SearchText%' OR AF2 LIKE '%SearchText%' ... OR AFZ LIKE '%SearchText%'
OR Author_ID IN (SELECT AuthorID FROM Books
WHERE BF1 LIKE '%SearchText%' OR BF2 LIKE '%SearchText%' ... OR BFZ LIKE '%SearchText%')
Esta expresión selecciona los registros Authors que tienen (i) un campo Authors que coincide con el texto de búsqueda o (ii) cualquier registro Books que tenga un campo que coincida con el texto de búsqueda. Tenga en cuenta que si la búsqueda en los registros Books relacionados devuelve una coincidencia, el registro principal que se selecciona es Authors.
Es importante recalcar que cuando se seleccionan los registros Authors se seleccionan también todos los registros Books relacionados, incluso aunque ninguno de ellos o no todos contengan el texto de la búsqueda. En la sección siguiente, Eliminar libros que no coinciden, explicamos cómo mostrar solamente los libros que contienen el texto de la búsqueda.
Eliminar libros que no coinciden
Los registros Authors seleccionados se devuelven con todos sus registros (secundarios) Books relacionados (véase la discusión de más arriba), por lo que existen varias posibilidades:
•El texto de la búsqueda se encuentra en la tabla Authors. En este caso podemos ver los detalles del autor junto con todos los registros Books relacionados de ese mismo autor.
•El texto de la búsqueda se encuentra en una de las tablas Books relacionadas de un registro Authors. En este caso deberíamos ver solamente los detalles del autor y los de los libros que coinciden con el texto de la búsqueda. Un método de conseguir esa vista es eliminar los libros que no coinciden de la fuente de página $BookCatalog. En nuestro ejemplo lo que hemos hecho es añadir una acción Eliminar nodo(s) al botón Buscar después de que se vuelva a cargar la fuente de página (imagen siguiente)
for $text in lower-case($PERSISTENT/Root/SearchText), $author in $BookCatalog/DB/RowSet/Row return $author/Books/Row [not(contains(lower-case(@Title), $text))] [not(contains(lower-case(@ISBN), $text))] [not(contains(lower-case(@Publisher), $text))] [not(contains(lower-case(@Genre), $text))] [not(contains(@Year, $text))] [not(contains(@Price, $text))] [not(contains(lower-case(../../@AuthorName), $text))] [not(contains(lower-case(../../@Website), $text))] [not(contains(lower-case(../../@Country), $text))]
|
La expresión XPath de la acción Eliminar nodo(s) funciona así:
•La variable $text contiene una variante en minúsculas de la cadena de búsqueda. Así se habilita la búsqueda con diferenciación entre mayúsculas y minúsculas.
•Los nodos que se devuelven para eliminar se seleccionan de los registros Books que descienden del autor actual.
•Los libros que se seleccionan para eliminar no deben contener la cadena de búsqueda en ninguno de los campos Books relevantes. Para indicar esto debe generar una secuencia de filtros predicados donde cada uno de ellos esté entre corchetes. Todos los predicados deben evaluar en true para que el libro se pueda eliminar. Si uno de los predicados evalúa en false (lo que ocurriría si la cadena de búsqueda existe en el campo marcado en ese predicado), el registro Books actual no se selecciona para eliminar y se marca el libro siguiente.
•Tenga en cuenta que los filtros predicados no solo comprueban los campos de los registros Books, sino también los campos del registro Authors principal (véanse los tres últimos predicados).
Borrar la cadena de búsqueda
Una vez se haya realizado la búsqueda, la fuente de página $BookCatalog contendrá solamente los registros Authors y Books que haya devuelto la búsqueda con el mecanismo que acabamos de explicar. El botón Borrar (véase la primera imagen de este apartado) elimina la cadena de búsqueda y vuelve a cargar la fuente de página $BookCatalog para que contenga todos los registros Authors. A continuación puede ver las acciones del botón Borrar.
La acción Actualizar nodo(s) cambia el nodo $PERSISTENT/Root/SearchText para que contenga la cadena vacía. Este nodo está asociado con el campo de edición en el que se introduce el texto de la búsqueda, por lo que el valor de la cadena vacía aparece en el campo de edición, es decir, borra lo que contuviera (consulte la sección «La cadena de búsqueda» más arriba). Al volver a cargar la fuente de página $BookCatalog con el conjunto de nodos $PERSISTENT/Root/SearchText en la cadena vacía carga todos los registros Authors en la fuente de página (véase la descripción de la función DBSQLSearch() más arriba).