Nodo COLL


La colección (COLL) es el nodo más importante del fichero mappings.xml y de forma muy simple podríamos definir a una colección como una vista de datos correspondiente a una tabla ó consulta de la Base de Datos, que a su vez, como es lógico, puede enlazar con otras tablas o consultas.

Evidentemente, lo anterior es una descripción simple de este nodo, en el cual no sólo se define la visualización en pantalla, también se definen los tipos de datos correspondientes en la BD, las relaciones con otras tablas, las reglas de negocio que afectan a la colección, las formas de filtrado, comportamientos…etc.

La maquinaria que provee CGSOFT, se encarga de transformar la definición de las colecciones del fichero mappings.xml en forma de colecciones de objetos, de forma que no trabajemos directamente con una BD y podamos abstraernos por completo del almacenamiento.

Una colección se puede ver de varias formas :

  1. En forma de Grid (listado).
  2. En forma de Formulario, cuando estamos introduciendo datos.
  3. En forma de Árbol.
  4. En forma de Calendario.
  5. En forma de Gráfico (para determinadas aplicaciones).


Aquí vemos una captura de una colección cuando estamos en modo de introducción de datos:

Captura de una colección cuando estamos en modo de introducción de datos

Como podemos ver, una colección en modo inserción de datos corresponde con un formulario, el cual puede dividirse en pestañas para organizar mejor los diferentes datos a rellenar.

Los campos ID y ROWID son OBLIGATORIOS en todas las tablas.
<collprops type="general">
<coll name="ParteDiario" ... sql="SELECT ..." objname="Documentos" updateobj="Documentos" progid="ASData.CASBasicDataObj" ...>
 
       <!-- GRUPOS O PESTAÑAS EN QUE VOY A DIVIDIR LA COLECCION -->
       <group name="Ficha" id="1"></group>
       ...
 
        <!-- PROPIEDADES DE ENLACE CON OTRAS COLECCIONES -->
	<prop name="IDSERIE" group="1" visible="0" type="N" mapcol="Series" mapfld="ID" keep="true"></prop>
        ....
 
	<!-- GRUPO 1 (dejar incluso este comentario para separar los props de los distintos grupos)-->
	<prop name="FECHA" visible="7" group="1" labelwidth="8" type="D" fieldsize="8" size="10">FECHA</prop>
        ....
 
	<!-- GRUPO 2 -->
	<prop name="MAP_ETQ1" group="2" visible="1" labelwidth="20" type="TL" fieldsize="25" bgcolor="#008030" forecolor="#FFFFFF">Recursos Propios</prop>
        ...
 
	<!-- CAMPOS NO VISIBLES PERO NECESARIOS -->
	<prop name="MAP_SIMTIPO" visible="0" group="1" type="T" fieldsize="4" size="4" linkedto="IDTIPODOC" linkedfield="SIMBOLO"></prop>
	...
 
        <!-- REGLAS DE NEGOCIO -->
	<create>
		<action name="setval" field="FECHA" value="##NOW##"></action>				
	</create>
        ...
        ...
        <!-- FIN DE LAS REGLAS DE NEGOCIO  -->
 
	<!-- NODO PARA GESTIONAR LOS FILTROS DE BUSQUEDA -->
	<asfilter fontsize="8" left="12" sort="false">
		<field name="NUMCOMPLETO" fldname="NUMCOMPLETO" oper="##FLD## LIKE '##VAL##%'" width="15" tooltip="Albaran" newline="false">ALBARAN</field>
                ...
	</asfilter>
</coll>
</collprops>

NOTAS IMPORTANTES

  • Normas a seguir para la programación en XOne:
    • Las palabras reservadas de SQL y los nombres de campos se pondrán en MAYUSCULAS.
    • Los campos ID de enlace con otras colecciones se llamarán IDLOQUESEA todo junto.
    • Los name de los Prop deben ir en MAYUSCULAS.
    • Los nodos del xml se pondrán todos en minúsculas.
  • Los campos que se incluyen en la selección y que proceden de una tabla enlazada deben precederse del prefijo “MAP_”. Esto le indica a los objetos de datos que es un campo que no se debe escribir en la base de datos. Las campos procedentes de tablas enlazadas no se pueden escribir, por lo que los únicos campos que son de lectura-escritura son los que pertenecen al objeto principal de la consulta.

Los atributos obligatorios en el Nodo <COLL> son:

  1. name
  2. sql
  3. objname
  4. updateobj
  5. progid.


Este atributo le asigna nombre a la colección.

Toda colección debe tener un nombre único para poder referirse a ella.

No puede haber dos colecciones con el mismo nombre dentro de la misma aplicación en ejecución para el mismo tipo de usuario.

Si hubiesen dos nombres de colección repetidos, se cogería el último que se haya definido en el XML.


Este atributo contiene una sentencia SQL que será utilizada para leer los datos de la colección, todo campo que vaya a aparecer en pantalla o se necesite que coja valor para utilizarlo posteriormente, debe rescatarse en la SQL.

Se pueden combinar varias tablas mediante uniones (JOIN) pero no mediante igualdades de campos, ya que la sentencia SQL no debería tener cláusulas WHERE (utilizar atributo filter para especificar el WHERE).

Los nombres de tablas pueden hacerse preceder de un prefijo que será sustituido por los controles de acceso a datos.

Esto permite que se puedan tener tablas correspondientes a varias aplicaciones dentro de la misma base de datos. En caso de que el SQL tenga cláusulas WHERE, éstas deberían incluirse en un sub-query (atributo filter) o en alguna estructura similar para evitar que la maquinaria conforme sentencias que sean sintácticamente incorrectas.

En colecciones pequeñas, podemos hacer un “SELECT * FROM …”, cuando la SQL vayamos a especificarla campo a campo, tenemos que tener en cuenta que siempre habremos de rescatar el campo ID de la tabla principal.
<coll name="ParteDiario" title="el parte diario" forprint="false" sql-debug="true" 
	sql="SELECT d.ID,d.IDSERIE,d.IDEMPRESA,d.IDTIPODOC,d.IDMONEDA,d.IDUSUARIO,d.IDOBRA,
	d.FECHA,d.NOMCLIENTE,d.DIRCLIENTE,d.PERSCONTACTO,d.OBSERV,d.FOTO,d.FIRMA1,
	d.FIRMA2,d.NUMERO,d.OPTIONS,
	s.SERIE AS MAP_SERIE,
	td.SIMBOLO AS MAP_SIMTIPO,
	o.CODIGO AS MAP_CODIGO,o.NOMBRE AS MAP_OBRA
	FROM ((((##PREF##Documentos d
	LEFT OUTER JOIN ##PREF##TiposDocumento td ON d.IDTIPODOC=td.ID)
	LEFT OUTER JOIN ##PREF##Empresa e ON d.IDEMPRESA=e.ID)
	LEFT OUTER JOIN ##PREF##Series s ON d.IDSERIE=s.ID)
	LEFT OUTER JOIN ##PREF##Obras o ON d.IDOBRA=o.ID)" 
	 objname="Documentos" updateobj="Documentos" progid="ASData.CASBasicDataObj" editwidth="66" editheight="69" filter="MAP_SIMTIPO='PD'">


El ejemplo anterior define una colección cuya instrucción SQL selecciona los datos de la tabla Documentos.

El prefijo ##PREF## será sustituido por la aplicación cuando se vayan a realizar operaciones de datos.

En caso de que la aplicación no tenga definido ningún prefijo, la palabra reservada ##PREF## será eliminada de la instrucción SQL, por lo que no causará errores.

En caso de que se utilice un prefijo, este será colocado en el lugar de ##PREF##.

Por ejemplo, si se le indica a la aplicación de datos que el prefijo a usar es “App”, la instrucción anterior quedará de la siguiente forma:

	FROM ((((App_Documentos d
	LEFT OUTER JOIN App_TiposDocumento td ON d.IDTIPODOC=td.ID)
	LEFT OUTER JOIN App_Empresa e ON d.IDEMPRESA=e.ID)
	LEFT OUTER JOIN App_Series s ON d.IDSERIE=s.ID)
	LEFT OUTER JOIN App_Obras o ON d.IDOBRA=o.ID)

Este atributo contiene el nombre del objeto de datos principal en la sentencia SQL que se utiliza para leer los datos de la base de datos. En el ejemplo anterior, el nombre del objeto principal será sin lugar a dudas la tabla “Documentos”, pero esto no siempre es tan evidente. En caso de que se trate de una unión de varias tablas, objname debe ser aquella tabla de la cual dependen las demás tablas de la instrucción SELECT.

Este atributo se emplea para indicarle a los objetos de datos cuál es la tabla que se utiliza para escribir en la base de datos. En general este atributo coincide con objname en un 99,9% de las veces, pero esto no tiene por qué ser así.

Por ejemplo, objname puede ser un nombre de una consulta en la base de datos, la cual contiene varias tablas unidas, por lo que no puede usarse para escribir.
IMPORTANTE: El atributo objname tiene que ser OBLIGATORIAMENTE una tabla, pues se usará para escribir datos.

Este atributo se emplea para decirle a la colección de qué tipo son los objetos que maneja, CGSOFT provee de un cierto número de bibliotecas que hacen que la colección tenga unos comportamientos predefinidos:

*  **ASData.CASBasicDataObj**: Contiene los comportamientos básicos de una colección. Si no se quiere realizar algún control especial, este es la clase que deben utilizar todas las colecciones que se crean en nuestro mappings.
*  **ASGestion.CASUser**: Contiene comportamientos relacionados con el control de usuarios. 
* 

Este atributo le indica a la colección una condición que deberá aplicarle a los registros que seleccione mediante la instrucción especificada en el atributo “sql”. NO es necesario poner la palabra “WHERE”. Puede interpretarse este atributo como la parte WHERE de la sentencia SQL.

Se coloca separado el filtro de datos del resto de la sentencia SQL porque durante la selección de datos se pueden adicionar otros filtros, que serán adicionados a éste. Este campo es opcional. En caso de no colocarse valor en él se seleccionarán todos los registros de la consulta, a menos que haya algún otro criterio de selección embebido dentro de la sentencia SQL (esto se hace mucho en los listados complejos).
El filtro de datos permite la utilización de la macro ##ENTID## (u otras similares). Durante la ejecución de la aplicación, estas macro serán sustituida por los valores que se manejen en cada caso. En el caso de la macro ##ENTID## y que no haya ninguna empresa activa o que la aplicación de datos no trabaje con empresas, esta macro se sustituye por NULL. La sustitución se efectúa de manera inteligente, así un filtro del tipo IDEMPRESA=##ENTID## con una empresa inexistente o sin trabajar con empresas, será sustituido por “IDEMPRESA IS NULL”.


Este atributo permite ordenar los datos de una colección por el(los) campo(s) que desee el programador. NO es necesario poner las palabras “ORDER BY”.
Por defecto las colecciones no llevan ordenamiento, sin embargo puede ser deseable que los datos aparezcan con un orden por defecto al mostrarse en pantalla.
La aplicación de filtros posteriormente durante la ejecución del programa cambiarán el valor del ordenamiento de la colección, sin embargo, cada vez que se inicie el programa, el ordenamiento será iniciado con este valor.

El atributo sort puede tomar como valor una lista de campos separados por comas de la misma forma que utiliza la sentencia ORDER BY en una instrucción SELECT. Los campos pueden estar seguidos de los atributos DESC o ASC para indicar orden descendente o ascendente (este último no es necesario especificarlo explícitamente, al ser el que se reconoce por defecto).

Decide si los datos de esa colección van a ser refrescados cuando se regrese de una ventana, pero solo si en esa ventana se produjo algún cambio.
Si no se define este atributo su valor por defecto es false.

Este atributo, que se define a nivel de colección, indica si hay que llenar o no el grid con los datos de la colección donde se define.
Toma los valores: true o false, por defecto se toma el valor true.
Este atributo se interpreta en el Frame.

Este atributo, disponible en Android, provoca que en los contents y en las colecciones se puedan refrescar los datos tirando desde el tope de la lista.


Con el fin de optimizar los tiempos de carga de la aplicación, si nos encontramos con una colección que tiene gran número de pestañas, podemos hacer que no se precarguen en memoria todas desde un inicio y limitar así el número de pestañas en memoria y los tiempos de pintado de la pantalla.

Para esto se ha implementado el atributo page-limit-off a nivel de colección, por defecto si no se especifica nada, page-limit-off=“6”.


Es un nuevo tema en los tabs de los grupos.

Se activa con el atributo a nivel de colección de group-theme=“material”.

Puede ser de dos tipos fijo o escroleable:

  1. Fijo significa que pondrá todos los tabs en lo ancho de la pantalla para que no se tenga que hacer scroll con el atributo. Mediante el atributo tab-mode=“fixed”.
  2. Escroleable significa que dibujará los tabs según lo que ocupe su título, uno al lado del otro y si no caben en pantalla se habilitará el scroll. Mediante el atributo tab-mode=“scrollable”.


Contribuciones

Pedro Santos Pantoja psantos@cgsoft.es