Galerías anidadas en Power Apps con SQL sin consultas adicionales

  • 15 Dic 2022
  • Power Apps, MSSQL

Escenario

Imaginemos por un instante un simple modelo de datos que sirva a gestionar una jerarquía con inmediatos n descendientes. Por ejemplo, un libro de recetas e ingredientes, órdenes de compra, proyectos y actividades. Padres e hijos. Datos que para visualizarlos en Power Apps se podría simplemente crear una Gallery por ejemplo con las recetas y dentro de ella crear otra Gallery que filtre sus items cuando receta_id es igual a ThisItem.id. Esta configuración obligará a Power Apps a realizar una consulta sobre la tabla de ingredientes para cada receta, lo que seguramente desde un punto de vista de las prestaciones no es lo mejor del mundo. Además, si quisiéramos filtrar la Gallery a través de un campo de texto, no podríamos filtrar recetas por ingredientes ya que los items de la Gallery está compuesta por la table receta.

Una sola consulta

Si pudiéramos incluir recetas y todos los ingredientes dentro una vista el problema estaría resuelto. Lamentablemente, si creáramos una vista con un simple LEFT JOIN las columnas de cada receta se repetirían n veces cuantos ingredientes cuente. Un desastre para el usuario.

Gracias al recién llegado ParseJSON (aún función experimental, pero que seguro llegó para quedarse) sería posible decodificar una columna de nuestra vista que devuelva todos los ingredientes agrupados en JSON (ver FOR JSON).

Hasta la vista

El primer paso es crear la vista en SQL. Para devolver hijos agrupados en formato JSON utilizaremos FOR JSON

La consulta debería ser más o menos así:

CREATE VIEW [schema].[receta_detalles]
AS
SELECT
  r.*, 
  (
    SELECT 
      * 
    FROM 
      receta_ingredientes 
    WHERE 
      receta_id = r.id FOR JSON PATH) AS ingredientes
FROM            
  receta

Vista con JSON en Power Apps

Ahora que temenos nuestra vista con la columna ingredientes en formato JSON vamos a crear en Power Apps una Gallery con la vista receta_detalles en la propiedad items. Luego, vamos a crear otra Gallery dentro la primera donde vamos a convertir el JSON de la columna ingredientes en una tabla. Previamente, será necesario (por lo menos al momento de este artículo) habilitar la función experimental ParseJSON.

El Código del parámetro items debería verse más o menos así:

SortByColumns(
    ForAll(
        Table(ParseJSON(ThisItem.ingredientes)),
        {
            ingrediente: Text(Value.ingrediente),
            cantidad: Value(Value.cantidad),
            depth: Value(Value.depth)
        }
    ),
    "depth",
    Ascending
)

De este modo hemos evitado a Power Apps el echo de tener que realizar una consulta a SQL sobre los igredientes de cada receta. Todo con una sola llamada.

Otro beneficio de esta solución es que teniendo todos los datos en una única vista será muy simple realizar una búsqueda de todas las recetas que contengan x ingrediente. Será suficiente crear un campo de texto y en la propiedad items de la Gallery raíz escribir:

SortByColumns(
    Search(
        Filter(
            'schema.receta_detalles,
            Or(
                created_by = cmbRecetaCreatedFilter.Selected.id,
                IsBlank(cmbRecetaCreatedFilter.Selected.id)
            )
        ),
        txtRecetaFilter.Text,
        "ingredientes"
    ),
    "created",
    Descending
)