Me sucedió trabajar en un proyecto que usaba el Work With Pattern y precisaba filtrar la información a mostrar utilizando como filtros valores que venian dados de antes.
En particular quería mostrar en el WWCustomer solo los clientes de determinado país (el país asociado al usuario que estaba logueado), pero podrían aplicar a multiples casos.Mi tendencia inicial fue utilizar cookies.
Es decir, en el login determinar el país correspondiende al usuario y hacer un "setCookie("Country", CountryId)".
Luego en el WWClientes simplemente agregar la condición: CountryId=getCookie("Country")
Si bien esto me funcionó había dos cosas que no me convencieron:
1. Parece un esquema algo "débil" en el sentido que no está formalizado que esa es información de contexto importante para el WW. Cualquiera podría modificar esa cookie con otro valor o directamente eliminarla y mi esquema dejaría de funcionar.
2. Al utilizar esa condición (con el "getcookie") la misma no va en el SELECT resultante lo cual puede significar una pérdida de performance, etc.
Dejemos lo del esquema "débil" de lado porque es algo "opinable", lo que si me preocupaba era la performance, paginado, etc, porque ahí es claro: es mejor que la condición sea parte del SELECT resultante de modo que la consulta la resuelva el DBMS.
¿Cómo hacer que la condición vaya en el SQL?
Fácil, se puede asignar una variable en el evento start y filtrar por ella.
El problema con esto es que si modifico los eventos del WWCustomer entonces pierdo el dinamismo de esa parte con el Pattern y es algo que no quiero perder.
Ahí apareció la solución de usar el contexto.
Es bastante simple:
1. En lugar de un SetCookie lo que se hace es agregar al SDT:Context el elemento que se desea mantener, en mi caso el CountryId:
y luego en el programa que hacía el SetCookie lo que hago es invocar al procedure SetContext:
2. Una vez que lo tengo “seteado” en el contexto luego solo debo poner la condición en la instancia del Pattern: CountriId=&Context.CountryId
¿Cómo funciona?
Es bastante sencillo, en el objeto WWCustomer se crea automáticamente la variable &Context basada en el SDT:Context. Esa variable tiene como “Initial Value” el procedure “LoadContext” que es el que se encarga de instanciar &Context con lo que se tiene almacenado en la sesión.
En resumen, todo me queda optimizado y mantengo la automatización, el dinamismo con el pattern, etc.
Moraleja: si usa el WorkWith Pattern préstele atención al manejo del Context, es algo que está bueno para resolver varios casos del estilo.
Hay una KB con un ejemplo sencillo en el GXServer Publico
En particular quería mostrar en el WWCustomer solo los clientes de determinado país (el país asociado al usuario que estaba logueado), pero podrían aplicar a multiples casos.Mi tendencia inicial fue utilizar cookies.
Es decir, en el login determinar el país correspondiende al usuario y hacer un "setCookie("Country", CountryId)".
Luego en el WWClientes simplemente agregar la condición: CountryId=getCookie("Country")
Si bien esto me funcionó había dos cosas que no me convencieron:
1. Parece un esquema algo "débil" en el sentido que no está formalizado que esa es información de contexto importante para el WW. Cualquiera podría modificar esa cookie con otro valor o directamente eliminarla y mi esquema dejaría de funcionar.
2. Al utilizar esa condición (con el "getcookie") la misma no va en el SELECT resultante lo cual puede significar una pérdida de performance, etc.
Dejemos lo del esquema "débil" de lado porque es algo "opinable", lo que si me preocupaba era la performance, paginado, etc, porque ahí es claro: es mejor que la condición sea parte del SELECT resultante de modo que la consulta la resuelva el DBMS.
¿Cómo hacer que la condición vaya en el SQL?
Fácil, se puede asignar una variable en el evento start y filtrar por ella.
El problema con esto es que si modifico los eventos del WWCustomer entonces pierdo el dinamismo de esa parte con el Pattern y es algo que no quiero perder.
Ahí apareció la solución de usar el contexto.
Es bastante simple:
1. En lugar de un SetCookie lo que se hace es agregar al SDT:Context el elemento que se desea mantener, en mi caso el CountryId:
y luego en el programa que hacía el SetCookie lo que hago es invocar al procedure SetContext:
2. Una vez que lo tengo “seteado” en el contexto luego solo debo poner la condición en la instancia del Pattern: CountriId=&Context.CountryId
¿Cómo funciona?
Es bastante sencillo, en el objeto WWCustomer se crea automáticamente la variable &Context basada en el SDT:Context. Esa variable tiene como “Initial Value” el procedure “LoadContext” que es el que se encarga de instanciar &Context con lo que se tiene almacenado en la sesión.
En resumen, todo me queda optimizado y mantengo la automatización, el dinamismo con el pattern, etc.
Moraleja: si usa el WorkWith Pattern préstele atención al manejo del Context, es algo que está bueno para resolver varios casos del estilo.
Hay una KB con un ejemplo sencillo en el GXServer Publico
Esta misma técnica yo la utilizo para hacer mis aplicaciones multitenant. Basta con poner el TenantId en el context, también en el momento del login como en el ejemplo de Gustavo, y luego en cada WW agregar la condición TenantId=&context.TenantId.
ResponderBorrarEsto me lleva a pensar que no parece muy complicado potenciar al pattern Work With, para que tenga la opción de ayudarnos a crear aplicaciones multitenant.
Imaginemos que exista una propiedad de la kb que sea Multitenant true o false, y si fuera true, que solicite informar el atributo que sea Id de la entidad Tenant. Luego en cada instancia de WW también una propiedad que sea Multitenant true, false o “Use environment property value”, esto es porque probablemente existan algunas entidades compartidas por los distintos tenant, por ejemplo Países.
Con esto el Genexus ya dispondría de la información como para agregar en las condition de cada objeto el filtro por tenant; y lo que parecería más difícil, agregar en la estructura el TenantId, pero bueno, ya tenemos el Category pattern que toca la estructura cuando es aplicado.
Para el equipo de desarrollo de Genexus seguramente no será tan simple de hacerlo como para mí describirlo (habría que resolver el tratamiento de autonuméricos, por ejemplo), pero me parece una idea alineada con lo que a futuro van a necesitar todos los sistemas y de paso se agrega funcionalidad al viejo pattern Work With que si bien es muchísimo lo que aporta actualmente, a veces extraño poder hacer un prompt o hacer múltiples WW para una misma transacción como lo hacía en las primeras versiones sobre la 9.0. También se me ocurre que por el porte del cambio, podríamos recibirlo en algún Ux de la evo 1 y no esperar hasta la evo 2 con las alternativas que Artech está evaluando según una conferencia que presencié en el encuentro.
Saludos.
Marcelo Arias
marcelo.arias@saasforeach.com
Marcelo,
ResponderBorrarCompartimos la importancia del tema y se está trabajando en eso (que hacer app multitenant sea basicamente una propiedad), incluso Federico Azzato dio una charla en el XX Encuentro (http://www.events.genexus.com/portal/hgxpp001.aspx?16,73,1248,O,S,0,,2185) no tengo claro el status a hoy e incluso hay unos cuantos casos "divertidos" como formulas, etc, pero seguro es un objetivo a cubrir en el corto plazo.
Saludos,
Gustavo