How to: Ejemplos de Data Providers con condiciones
El uso de “condiciones” en los data providers permite darle mayor potencia expresiva a los mismos y así brindar una solución versátil para distintos tipos de “output".
En GeneXus X hemos incorporado el nuevo tipo de objeto Data Provider. A modo de pequeña introducción para aquellos que aún no lo conozcan, los Data Providers son un objeto declarativo que sustituye a una determinada clase de procedimientos: aquellos que reciben una entrada, realizan un proceso y su objetivo final es devolver un conjunto de datos en un formato estructurado, o sea el foco esta puesto en la salida.
De este modo se define el formato de la salida del Data Provider y eso lo transforma en un objeto más declarativo que un procedimiento pues pone el énfasis en “qué hacer” en lugar de “cómo hacerlo”
Los componentes básicos de los Data Providers son los Grupos, Elementos, Variables, Subgrupos y opciones avanzadas de control para los Grupos (Defaul clause, Paginate clause, NoOutput clause, OutputIfDetail clause e Input clause).
Más detalles en el CommunityWiki
El objetivo de este How to es mostrar dos ejemplos de uso interesantes.
El primero a efectos de mostrar que en las condiciones Where de los grupos no sólo puedo agregar condiciones donde el lado izquierdo de la comparación sea un atributo sino también pueden ser variables.
Supongamos que queremos obtener una lista de empleados con sus datos, este sería el Data Provider:
Ahora, si tuvieramos la necesidad de condicionar la salida dependiendo de si el usuario está autorizado a ver esa información o no, podría agregar la siguiente condición:
En este caso se agrega el filtro a la sentencia SQL generada, la cual sería la siguiente:
Incluso si quisiera devolver siempre los datos, pero solamente mostrar la dirección para aquellos usuarios autorizados, podría hacer lo siguiente:
En este caso se genera la sentencia select pero sin la condición de filtro, la cual se transforma en un IF en el fuente del Data Provider :
Nota: si en lugar de un grupo de atributos (Adress, Salary, etc) se quiere filtrar solo un valor se puede escribir directamente:
EmployeeAddress = EmployeeAddress if &UsrAut=”S”;
Veamos otro ejemplo interesante:
Supongamos en este ejemplo que tenemos una aplicación que maneja Clientes y Prospects (los Clientes están en una tabla y los Prospects en otra). Se quiere escribir un Data Provider el cual devolverá una Collection que contenga los Clientes o Prospects Activos.
El Data Providers recibirá como parámetro si se quieren ver Clientes o Prospects:
Una forma de escribirlo es la siguiente:
DSClientesActivos define el filtro sobre Clientes y DSProspectsActivos hace lo análogo pero en la tabla de Prospects.
Notar que esto ejecutara siempre los dos selects pero agregara al where el valor de &FiltrarPor recibido como parámetro por el Data Providers (por lo tanto uno devolverá datos y el otro no).
Esto genera:
Sin embargo podemos escribir el Data Provider como sigue, para que no ejecute siempre los dos selects, sino solamente el que corresponde de acuerdo al parámetro &FiltrarPor (es en el fuente generado donde se decide que select ejecutar).
De este modo se define el formato de la salida del Data Provider y eso lo transforma en un objeto más declarativo que un procedimiento pues pone el énfasis en “qué hacer” en lugar de “cómo hacerlo”
Los componentes básicos de los Data Providers son los Grupos, Elementos, Variables, Subgrupos y opciones avanzadas de control para los Grupos (Defaul clause, Paginate clause, NoOutput clause, OutputIfDetail clause e Input clause).
Más detalles en el CommunityWiki
El objetivo de este How to es mostrar dos ejemplos de uso interesantes.
El primero a efectos de mostrar que en las condiciones Where de los grupos no sólo puedo agregar condiciones donde el lado izquierdo de la comparación sea un atributo sino también pueden ser variables.
Supongamos que queremos obtener una lista de empleados con sus datos, este sería el Data Provider:
EmployeeCollection { EmployeeItem { Id = EmployeeId Name = EmployeeDsc Address = EmployeeAddress } } |
Ahora, si tuvieramos la necesidad de condicionar la salida dependiendo de si el usuario está autorizado a ver esa información o no, podría agregar la siguiente condición:
EmployeeCollection { EmployeeItem Where &UsrAut=”S” { Id = EmployeeId Name = EmployeeDsc Address = EmployeeAddress } } |
En este caso se agrega el filtro a la sentencia SQL generada, la cual sería la siguiente:
SELECT [EmployeeId], [EmployeeDsc], [EmployeeAddress] FROM [Employee] WITH (NOLOCK) WHERE @AV1UsrAut = “S” ORDER BY [EmployeeId] |
Incluso si quisiera devolver siempre los datos, pero solamente mostrar la dirección para aquellos usuarios autorizados, podría hacer lo siguiente:
EmployeeCollection { EmployeeItem { EmployeeId EmployeeDsc EmployeeAddress [NoOutput] Where &UsrAut=”S” { EmployeeAddress = EmployeeAddress; EmployeeSalary = EmployeeSalary; } } } |
En este caso se genera la sentencia select pero sin la condición de filtro, la cual se transforma en un IF en el fuente del Data Provider :
Select a ejecutar: SELECT [EmployeeId], [EmployeeDsc], [EmployeeAddress], [EmployeeSalary] FROM [Employee] WITH (NOLOCK) ORDER BY [EmployeeId] Y además en el fuente del DP: if ( AV1UsrAut = “S”) { Gxm1employee.gxTpr_Employeeaddress = A363Employee ; Gxm1employee.gxTpr_Employeesalary = A364Employee ; } |
Nota: si en lugar de un grupo de atributos (Adress, Salary, etc) se quiere filtrar solo un valor se puede escribir directamente:
EmployeeAddress = EmployeeAddress if &UsrAut=”S”;
Veamos otro ejemplo interesante:
Supongamos en este ejemplo que tenemos una aplicación que maneja Clientes y Prospects (los Clientes están en una tabla y los Prospects en otra). Se quiere escribir un Data Provider el cual devolverá una Collection que contenga los Clientes o Prospects Activos.
El Data Providers recibirá como parámetro si se quieren ver Clientes o Prospects:
Una forma de escribirlo es la siguiente:
Parm(&FiltrarPor) SDTCliProsCollection { SDTCliProsCollectionItem using DSClientesActivos() where &FiltrarPor = ‘CLIENTE’ { PartnerId = ClienteId PartnerName = ClienteName } SDTCliProsCollectionItem using DSProspectsActivos() where &FiltrarPor = ‘PROSPECT’ { PartnerId = ProspectId PartnerName = ProspectName } } |
DSClientesActivos define el filtro sobre Clientes y DSProspectsActivos hace lo análogo pero en la tabla de Prospects.
Notar que esto ejecutara siempre los dos selects pero agregara al where el valor de &FiltrarPor recibido como parámetro por el Data Providers (por lo tanto uno devolverá datos y el otro no).
Esto genera:
SELECT [ClienteTipo], [ClienteId], [ClienteNombre] FROM [Cliente] WITH (NOLOCK) WHERE (@AV4Filtrar = 'CLIENTE') AND ([ClienteStatus] = “Activo”) ORDER BY [ClienteId] SELECT [ProspectTipo], [ProspectId], [ProspectNombre] FROM [Prospect] WITH (NOLOCK) WHERE (@AV4Filtrar = 'PROSPECT') AND ([ProspectStatus] = “Activo”) ORDER BY [ProspectId] |
Sin embargo podemos escribir el Data Provider como sigue, para que no ejecute siempre los dos selects, sino solamente el que corresponde de acuerdo al parámetro &FiltrarPor (es en el fuente generado donde se decide que select ejecutar).
SDTCliProsCollection { SDTCliProsCollectionDummy [NoOutput] where &FiltrarPor = 'CLIENTE' { SDTCliProsCollectionItem using DSClientesActivos() { PartnerId = ClienteId PartnerName = ClienteNombre } } SDTCliProsCollectionDummy [NoOutput] where &FiltrarPor = 'PROSPECT' { SDTCliProsCollectionItem using DSProspectActivos() { PartnerId = ProspectId PartnerName = ProspectNombre } } } Select a ejecutar en caso de invocar al DP con &FiltrarPor = ‘CLIENTE’: SELECT [ClienteTipo], [ClienteId], [ClienteNombre] FROM [Cliente] WITH (NOLOCK) WHERE [ClienteStatus] = “Activo” ORDER BY [ClienteId] Y además en el fuente del Data Providers: if ( ( String.CompareOrdinal(AV4Filtrar.TrimEnd(' '), "CLIENTE".TrimEnd(' ') ) == 0 ) ) { AV10DSClie = AV2Cliente ; /* Using cursor P001R2 */ pr_default.execute(0, new Object[] {AV10DSClie}); while ( (pr_default.getStatus(0) != 101) ) { ………………………. (select con filtro por [ClienteStatus] = “Activo”) } pr_default.close(0); } if ( ( String.CompareOrdinal(AV4Filtrar.TrimEnd(' '), "PROSPECT".TrimEnd(' ') ) == 0 ) ) { AV12DSPros = AV3Prospec ; /* Using cursor P001R3 */ pr_default.execute(1, new Object[] {AV12DSPros}); while ( (pr_default.getStatus(1) != 101) ) { ……………………….(select con filtro por [ProspectStatus] = “Activo”) } pr_default.close(1); } this.cleanup(); |