COMO SIMULAR UNA FUNCION SESSION O VARIABLE GLOBAL EN WIN CON GENEXUS Y ORACLE 3. July 2007 by Fabricio De los Santos. Cuando trabajamos en Web y queremos distinguir una sesión de otra podemos utilizar una variable de tipo WebSession. Esto básicamente queda muy claro en cualquier ejemplo GeneXus generado por pattern s, etc. Un ejemplo puede ser el procedimiento SetContext de GxWiki &Session.Set(WikiParameters.Context, &Context.ToXml()) Básicamente seteamos en la variable de tipo WebSession algo particular, en este ca so un SDT que se llama context. Ahora bien, por que querría o precisaría tener algo similar a una WebSession pero en una aplicación Windows? Si bien desde siempre existen las funciones UserID() y Wrkst() que podrían darme e sa unicidad que preciso, dependiendo de la aplicación o de algunas limitantes o qu e nos encontremos, cantidad de licencias, etc, puede ser que ni la combinación de estas 2 funciones mencionadas, nos pueda garantir el dato de una sesión dentro de mi aplicación. Por ejemplo: Tengo una aplicación corriendo bajo Terminal Services con licencia para 10 usuario s, donde el nombre de usuario podría no indicarme nada en particular, digamos podría n ser del tipo User1, User2, etc, para lo cual si usara la función UserID() para g rabar una auditoría en un registro, no me serviría de mucho. New xxxx=yyyy xxxx=yyyy xxxx=UserID() EndNew Entonces podría llegar a otra solución Aplico un login y password en una pantalla cuando ingreso al sistema y lo asocio con UserID() Algo sencillo para ejemplificar (sin contemplar cientos de criterios de segurida d) sería más o menos así: For Each //Usuarios Where UsrCod=&UsrCod Where UsrPsw=&UsrPsw New //Log LogUsrID=UserID() LogUsrCod=UsrCod EndNew EndFor Para luego volver a mi rutina de auditoria New xxxx=yyyy xxxx=yyyy xxxx=udp(pUserID)
EndNew Donde pUserID seria una recorrida de la tabla Log usando como condición LogUsrID=User ID() y devolviendo como resultado el valor de LogUsrCod que podria ser Juan Perfecto, ahora si tengo un Usuario que conozco registrado para auditoría. Pero bien, complicándola un poco más, que pasaría si ese User1? (del Terminal) está ejecu tando mi aplicación y necesita ejecutar otra instancia? No habría problemas, porque si bien no podría hacer el New en la tabla de Log, con la nción UserID() obtendría el mismo dato, o sea Juan Pero Si este mismo User1? (del Terminal) en vez de entrar como Juan, necesita entrar com o Pedro? No podré hacer un New, y ni pensar de utilizar un When Duplicate porque reemplazaría u usuario por otro para dos sesiones distintas! Mmm Esto me hace pensar que a partir de la primera pantalla, tendré que pasar por paráme tro el usuario que se logueó. Es una solución un poco tediosa, porque objetos que no contemplé antes voy a tener que acomodar para recibir este parámetro. Sería una solución contar con una función WinSession() que me devuelva la sessión del us uario que está conectado a la base de datos. Claro, su funcionamiento interno sería particular para cada DBMS. Pero, por mientras esto no esté en GeneXus, podemos sim ularlo mezclando algunos ingredientes de Oracle y luego cada uno puede aplicarlo en su DBMS de desarrollo. 1) Debemos crear una view en nuestra base de datos. CREATE OR REPLACE FORCE VIEW MISESSION AS select userenv(SESSIONID) SESSIONID from dual; 2) En GeneXus, creamos un DataView a esa View de Oracle con un atributo para ide ntificar la sesión. 3) Luego creamos un procedimiento que nos devuelva la sesión, para esto, hacemos u n simple for each que recorra este data view, el cual para nuestra sesión solo va a devolver un registro. En mi ejemplo lo llame pmisession &MiSession=0 For Each //MISESISON Defined By SessionID &MiSession=SessionID EndFor Y listo, ahora simplemente en vez de utilizar la función UserId() o Wrkst(), llama ré a este procedimiento para obtener mi variable única. Y si eres demasiado cómodo (y sólo si estás acostumbrado con el underground de GeneXus ), puedes adicionar esta función personalizada a los archivos *func.pst en el director io de GeneXus con la sintaxis pmiession.Udp():Numeric para que de esta forma cuando la quieras utilizar, simplemente presionando Ctrl +
U, aparezca dentro de la lista de funciones. Otras de las posibilidades sería usar el comando SQL de GeneXus, pero lamentableme nte, no permite devolver resultados, si existiera una variante del mismo que per mitiera en algunos casos devolver un resultado único para almacenar en una variabl e GeneXus, podría ser algo parecido a esto: &sent=select userenv(SESSIONID) from dual; &misession= sql [!&sent!] Pero por ahora no existe. Observación: Puede parecer simple o de poco valor esta función de unicidad, pero realmente es a lgo útil. Hace unos años en otra empresa, implementamos un sistema con una KB que usaba la f unción Wrkst() (y todavía lo sigue usando) para mantener la unicidad, y para que cad a máquina corra en una sessión única, deshabilitamos la posibilidad que se ejecutara e l sistema más de una vez por máquina, justamente para tener esa unicidad, algo que h oy realmente se podría solucionar de esta forma, que ya existía en aquella época, pero a veces uno toma las cosas como vienen y basados en el lema lo que funciona no s e cambia, a veces perdemos eficiencia. Fabricio De los Santos Gerencia de Proyectos - Consultoría GeneXus ERP Sistemas de Misión Crítica - Bases de Datos. Vea mis blogs en: www.fabriciodelossantos.com