Relaciones entre Colecciones
En XOne hay tres tipos de relaciones entre colecciones:
Relación 1 a 1: Lupa
Este tipo de relación se utiliza para seleccionar un único valor de otra colección.
Únicamente se grabará en Base de Datos el ID de la fila seleccionada, pudiendo rescatar además, simplemente para mostrar en pantalla, otros campos de la fila seleccionada.
<prop name="IDCLIENTE" group="1" type="N" visible="0" mapcol="Clientes" mapfld="ID"/> <!-- Este campo es el que realmente SE GRABARÁ en la BD, normalmente no está visible. Enlaza con la colección "Clientes" y nos guardaremos el valor del campo "ID" seleccionado. --> <prop name="MAP_CLIENTE" ... linkedto="IDCLIENTE" linkedfield="NOMBRE" onchange="Refresh" value="##ID##">Cliente</prop> <prop name="MAP_CONTACTO" ... linkedto="IDCLIENTE" linkedfield="CONTACTO" locked="true" onchange="Refresh">Contacto</prop> <!-- Estos campos están asociados con el campo "IDCLIENTE". Al llevar el prefijo "MAP_" NO se graban en BD. Para obtener sus valores utilizan el campo "IDCLIENTE" (linkedto) como enlace a la otra colección. El linkedfield es el campo que mostraremos por pantalla, el cual nos traemos de la otra colección. La lupa aparece en el campo que no está locked="true", para poder buscar directamente desde él. Los demás campos podemos ponerlos con el locked="true" para que NO se pueda editar su contenido NI TAMPOCO salga la lupa. -->
Relación 1 a 1: Combo
Similar al anterior, pero se utiliza únicamente cuando la colección llamada tiene pocos datos.
Esto es importante, porque cuando se va a pintar la ventana de edición, y uno de los campos tiene un combo, cargará en memoria todos los valores que puede contener dicho combo, con lo que si son muchos datos a cargar en el momento de abrir dicha ventana de edición, puede demorarse bastante.
Vista campo de enlace de tipo Lupa en BlackBerry |
---|
Ejemplo de Código
<prop name="IDTIPO" group="1" type="N" visible="0" mapcol="Tiposvisitas" mapfld="ID"></prop> <!-- Este campo es el que realmente SE GRABARA BD, normalmente no está visible. Enlaza con la colección "TiposVisitas" y nos guardaremos el valor del campo "ID" seleccionado. --> <prop name="MAP_TIPO" ... type="T" linkedto="IDTIPO" linkedfield="DESCRIPCION" showinline="true">Tipo</prop> <!-- Este campo está asociado con el campo "IDTIPO". Al llevar el prefijo "MAP_" NO se graba en BD. Para obtener sus valores utiliza el campo "IDTIPO" como enlace a la otra colección. La diferencia con el control tipo "lupa" es el atributo showinline="true", que es realmente el que le da la apariencia de combo. -->
La diferencia con el tipo lupa es simplemente el atributo showinline=“true” y además el hecho de que el combo se carga de valores cuando se entra en la colección a diferencia de la lupa.
Relación 1 a 1: Combo pero SIN BASE DE DATOS AUXILIAR
La estructura es similar a los anteriores, pero se utiliza exclusivamente cuando la colección llamada tiene pocos datos y claramente definidos.
NO se tira contra una Tabla en Base de Datos, los valores se definen en un primer PROP y se rescatan en otro PROP.
Ejemplo de Código
<prop name="MAP_IDTIPO" visible="0" group="1" type="N" mapcol-values="COMERCIAL,DPT INTRODUCCION,RESPONSABLE S EXT"/> <!-- Al ser un MAP_ no se graba en BD y el atributo mapcol-values define los valores posibles, separados por comas. --> <prop name="DESTINATARIO" labelwidth="0" type="T" size="40" onchange="Refresh" fieldsize="23" visible="1" showinline="true" group="1" linkedto="MAP_IDTIPO" linkedfield="DATA"/> <!-- Este campo es el que se graba en BD, el atributo linkedfield siempre vale DATA. -->
Relación 1 a N: Contents
Una colección de contenido (contents) es un grupo de datos que dependen de una cabecera, es decir, una colección que depende de otra.
Se utiliza cuando no sabemos el número de registros que vamos a poder asociar en la colección cabecera.
Ejemplos típicos de contents son los pedidos y sus líneas de detalle o artículos y sus existencias en almacén.
Para definir colección con content es necesario seguir varios pasos:
Pasos para crear un Content
Paso 1
Se debe definir la colección principal (p.e colección de documentos). Cada una de las propiedades que se definen en esta colección corresponde a la cabecera del objeto.
Se define la colección content.
En el ejemplo que estamos utilizando, se creará una colección de detalles de documento. Cada una de las propiedades que se definan en la colección, corresponderán a las líneas de detalle del documento.
Se incluye una definición de content en la colección principal. La definición de content tiene el siguiente formato:
<prop name="@NombrePropiedad" group="NumeroGrupo" type="Z" contents="nombre del content"></prop> <contents name="nombre del content" src="coleccion" filter="sentencia WHERE"></contents>
PROPS | |
---|---|
name | Le asigna un nombre a la propiedad. Se suele poner una “@” delante para indicar que es una propiedad que hace referencia a un content. Recomendamos su uso para distinguir y localizar con mayor facilidad dentro del mappings. |
group | Grupo o pestaña donde aparecerá el content. |
type | Tipo de propiedad. Para referirse a content ha de ser “Z”. |
contents | Nombre del content. Este atributo hace una llamada al nodo contents que tenga su mismo nombre. Es decir, el atributo contents ha de ser igual que el name del nodo contents. |
width | Define el ancho del content. |
height | Define la altura del content. En Android, es posible modificar este atributo por script. Supongamos que por ejemplo necesitas un cuadro de búsqueda que está oculto y que lo activas con un botón, y quieres que todo ocupe siempre el 100% de la pantalla. Entonces, lo que harías sería lo siguiente: |
<prop name="MAP_TAMCONTENT" visible="0" frame="id1" group="1" type="T" size="30" title="Tamaño content" /> <prop name="@MaquinasContent" frame="id4" group="1" type="Z" contents="MaquinasContent" width="100%" height="##FLD_MAP_TAMCONTENT##" onchange="Refresh" editmodal="true" forceonchange="true" mask="0" locked="true" /> <contents name="MaquinasContent" src="MaquinasContent" filter="IDCLIENTE=##FLD_MAP_IDCLIENTE##" /> <before-edit> <action name="runscript"> <script language="VBScript"> this("MAP_TAMCONTENT")="75%" <script> </action> <before-edit>
Ahora, mediante script modificarías el tamaño cuando quisieras del mismo modo.
CONTENTS | |
---|---|
name | Le asigna un nombre al content. Todo content tiene que tener un nombre, que deberá coincidir con el atributo contents, del punto anterior. |
src | Indica el nombre de la colección contents. Cada vez que se crea un objeto contenedor, la colección origen es copiada y se llena con aquellos objetos que le pertenezcan al contenedor únicamente. En el ejemplo que estamos poniendo (documento con líneas de detalle) el objeto contenedor es el documento (un objeto por cada registro de cabecera). Cada objeto contenedor tiene asignadas varias líneas de detalle (en una tabla enlazada) Los registros de la tabla enlazada se colocan en la colección de contenidos. |
filter | Es el filtro que indica cuáles registros de la tabla enlazada le “pertenecen” a este objeto en particular. Si la tabla de detalles se enlaza con la tabla principal por el campo IDDOCUMENTO, el filtro sería algo como IDDOCUMENTO=##ID##. Los componentes de datos se encargarán de sustituir la macro ##ID## por el ID del objeto propietario para cada uno de los documentos. |
Paso 2
Si lo que se quiere es enlazar el pedido con los detalles en el momento de grabar el pedido(padre), se definen las acciones necesarias para que durante la grabación del pedido se realicen los enlaces necesarios, para que en las tablas queden almacenados los valores correctos que determinen la relación entre los registros del detalle y el pedido en la Base de Datos.
Los códigos siguientes tienen el sentido de asignar al campo IDPEDIDO de los detalles el valor del ID del pedido de la colección de cabecera, de forma que queden enlazados los registros. (relación cabecera-detalles)
En la colección Pedidos (padre) habría que añadir el siguiente código:
<insert> <!-- Al grabar un nuevo pedido en base de datos, a cada detalle se le pone el ID del pedido creado --> <action name="link" coll="Detalles" field="IDPEDIDO" value="##ID##"></action> </insert>
En la colección Detalles (colección contenida ó hija) habría que añadir el siguiente código:
<create> <!-- Al crear una nueva línea de Detalle, al IDPEDIDO de ese detalle se le pone el ID del PEDIDO que estamos realizando --> <action name="setfldval" targetfld="IDPEDIDO" sourcefld="ID"></action> </create>
Ejemplo
Ejemplo de un combo para seleccionar la comunidad autónoma a la que pertenece un cliente:
<!-- Este código estaría en la colección "principal" de clientes, donde queremos el combo de valores --> <!-- Propiedad de tipo IDENLACE con otra colección --> <prop name="IDCOMUNIDAD" visible="0" type="N" mapcol="Comunidades" mapfld="ID"/> <!-- Propiedad de tipo MAPEADA --> <prop name="MAP_COMUNIDAD" type="T" labelwidth="8" title="COMUNIDAD" linkedto="IDCOMUNIDAD" linkedfield="NOMBRE" showinline="true"/>
Aquí tenemos la definición de la colección que aparece dentro de dicho combo.
<coll name="Comunidades" sql="SELECT * FROM ##PREF##Comunidades" objname="Comunidades" updateobj="Comunidades" progid="ASData.CASBasicDataObj" filter="" sort=""> <group name="General" id="1"> <prop name="NOMBRE" type="T" title="Comunidad:" width="90%" lmargin="5%" labelwidth="6" visible="15" /> </group> </coll>