Autor: Doug Hennig
Traducido por: Germán Giraldo G.
Generalidades
En FoxPro 2.x, los desarrolladores editaban los registros usando scatter memvar, editando las variables de memoria, y gather memvar. El propósito de de esta edición indirecta de campos era proteger el registro haciendo buffering. Con Visual FoxPro, el buffering de datos está incluido, así los campos pueden editarse directamente. Esta sesión discutirá cómo trabaja el buffering de datos y explora estrategias para seleccionar cuál mecanismo de buffering usar y cómo manejar conflictos multiusuario.
Introducción
Si usted ha pasado algún tiempo trabajando con VFP, una de las cosas que probablemente ha aprendido es que aunque usted puede continuar haciendo las cosas en la “vieja” forma si usted lo desea, VFP le da una forma mejor para realizar la misma tarea. Cómo editar los registros en un formulario es un perfecto ejemplo de esto.
Aquí está la “vieja” forma que yo usaba para escribir código para editar un registro en una pantalla de entrada de datos:
- La pantalla tiene objetos get para variables de memoria con el mismo nombre de los campos de la tabla (por ejemplo, M.CUST_ID y M.NAME).
- Cuando el usuario posiciona la tabla en un registro particular (por ejemplo, usando el botón “Siguiente”), usar scatter memvar para transferir el registro a las variables de memoria y show gets para refrescar los valores en la pantalla. El usuario no puede editar las variables (ellas están deshabilitadas o tienen una cláusula when que se evalúa a F.) a causa de que el usuarios actualmente está en el modo “ver”.
- Cuando el usuario elige el botón “Editar”, trata de bloquear el registro; muestra un mensaje apropiado si no podemos. Verificar el valor de cada campo contra su variable de memoria —si ellos no coinciden, otro usuario podría haberlo editado y guardado el registro desde que nosotros lo mostramos por primer vez. En ese cado, muestra un mensaje apropiado y usa scatter memvar y show gets de nuevo para que el usuario vea el contenido actual del registro.
- Si los campos y las variables de memoria coinciden, se habilitan los objetos get o hace que su cláusula when se evalúe a .T. para que el usuario pueda editar las variables.
- Cuando el usuario elige el botón “Guardar”, se hace alguna validación para asegurar que todo se entró de acuerdo a sus reglas, entonces usar gather memvar para actualizar el registro desde las variables de memoria y desbloquea el registro. Deshabilitar los objetos get o hacer que su cláusula when se evalúe a .F. para que el usuario esté de nuevo en el modo “ver”.
Buffering
Usar variables de memoria para mantener el contenido de un registro puede considerarse como crear un buffer de datos. Los datos se transfieren desde el registro al “buffer” usando scatter memvar y desde el “buffer” al registro con gather memvar. VFP no sólo puede hacer este tipo de buffering de un único registro (llamado buffering de fila o de registro) automáticamente, él también soporta otro tipo de buffering (llamado buffering de tabla) en el cual múltiples registros se accedan a través de un buffer. El buffering de registro se usa normalmente cuando usted desea acceder o actualizar un único registro a la vez. Esto es común en mecanismos de entrada de datos como los descritos antes: el usuario puede mostrar o editar un único registro en el formulario. El buffering de tabla debe elegirse para actualizar varios registros a la vez. Un ejemplo común es un formulario con cabecera-detalle de factura. Usando buffering de tabla para la tabla detalle de factura, usted puede permitirle al usuario editar tantas líneas de detalle como él desee, y entonces guardar o cancelar todos los registros de detalle a la vez. Además de los dos mecanismos de buffering, hay dos mecanismos de bloqueo. La “vieja” forma que describí antes puede considerarse un esquema de bloqueo pesimista —el registro se bloquea tan pronto como el usuario elige “Editar”, y permanece bloqueado hasta que él elige “Guardar”. Esto asegura que nadie mas puede hacer cambios al registro mientras el usuario lo esté haciendo, esta forma puede o no ser una buena cosa, dependiendo de su aplicación. El otro método que yo describí antes es un mecanismo de bloqueo optimista —el registro sólo se bloquea por el breve tiempo que toma escribir el registro, y se desbloquea inmediatamente. Esto maximiza la disponibilidad del registro (esto también se conoce como maximizar la simultaneidad) pero significa que tenemos que manejar conflictos que ocurren si dos usuarios editan el registro al mismo tiempo. Como veremos en un momento, actualmente esto es fácil de hacer en VFP, así el buffering optimista probablemente será el mecanismo elegido para la mayoría de las aplicaciones. Debido a que los registros pueden ser buffered automáticamente, ya no es necesario usar el mecanismo de “buffer manual”. En otras palabras, ahora nosotros podemos hacer read directamente contra los campos en el registro sin preocuparnos por el mantenimiento de variables de memoria para cada uno. Para guardar los cambios, simplemente le informamos a VFP que escriba el buffer en la tabla, y para cancelar los cambios, le informamos que no lo haga. En un momento veremos cómo hacerlo. VFP implementa el buffering creando un “cursor” cuando se abre una tabla. El cursor se usa para definir propiedades para la tabla. En el caso de tablas locales, la única propiedad para el cursor es cómo se realiza el buffering; para vistas y tablas remotas hay propiedades adicionales que van mas allá del alcance de esta sesión. Estas propiedades se establecen usando la función cursorsetprop() y se examinan con cursorgetprop(). Veremos resumidamente el uso de estas funciones. El buffering de tabla tiene una implementación interesante respecto a agregar registros: cómo se agregan los registros al buffer, se les asigna un número de registro negativo. recno() devuelve -1 para el primer registro agregado, -2 para el segundo, y así sucesivamente. Puede usar go con un número negativo para posicionar el buffer en el registro agregado apropiado. Esto tiene una implicación en las rutinas que manejan números de registro —en lugar de probar para between(lnRecno, 1, reccount()) para asegurar que lnRecno es un número de registro válido, usted ahora probará para between(lnRecno, 1, reccount()) or lnRecno < 0.
Usar Buffering
Buffering está desactivado por definición, así VFP actúa como FoxPro 2.x en términos de cómo se escriben las actualizaciones en una tabla. Para usar buffering, usted debe activarlo específicamente. Buffering está disponible para ambos: tablas libres y aquellas unidas a una base de datos. Buffering requiere que usted establezca set multilocks on debido a que por definición también está desactivado; usted obtendrá un mensaje de error si olvida hacer esto. Puede poner multilocks = on en su CONFIG.FPW o usar la función Options en el menú Herramientas para guardar esta configuración por definición. Buffering se controla usando cursorsetprop('Buffering', <n>, <Alias>). No tiene que especificar <Alias> si está configurando buffering para la tabla actual, <n> es uno de los siguiente valores dependiendo del método de buffering y bloqueo que desee usar:
Buffering/Método de Bloqueo | <n> |
sin buffering | 1 |
registro, pesimista | 2 |
registro, optimista | 3 |
tabla, pesimista | 4 |
tabla, optimista | 5 |
Para obtener: | Use: |
el valor que el usuario ha entrado (el valor en el buffer) | <fieldname> or <alias.fieldname> |
el valor antes que el usuario cambiara algo | oldval('<fieldname>') |
el valor actual en el registro | curval('<fieldname>') |
Campo | Valor | Oldval() | curval() |
LAST_NAME | Jones | Jones |
Jones |
FIRST_NAME | Bill | Bill | Bill |
Bob cambia el primer nombre a Sam pero todavía no ha guardado el registro:
Campo | Valor | Oldval() | curval() |
LAST_NAME |
Jones | Jones | Jones |
FIRST_NAME | Sam | Bill | Bill< |
Mary trae el registro #2 de CONTACTS.DBF, hace clic en el botón “Editar”, cambia el primer nombre a Eric, y guarda. En la máquina de Bill:
Field |
Value |
Oldval() |
curval() |
LAST_NAME |
Jones |
Jones |
Jones |
FIRST_NAME |
Sam |
Bill |
Eric |
- determinar cuáles campos cambió el usuario comparando el valor buffered con el valor original; y
- detectar si otros usuarios en la red han hecho cambios al mismo registro después de iniciar la edición, comparando el valor original con el valor actual.
Valor |
Descripción |
1 | Sin cambios |
2 | El campo fue editado el estado de borrado del registro ha cambiado |
3 | Se agregó un registro pero el campo no fue editado y el estado de borrado no ha cambiado. |
4 | Se agregó un registro y el campo fue editado o el estado de borrado del registro ha cambiado. |
Escribir un Registro Buffered
Continuando con el ejemplo anterior, ahora Bill hace clic en el botón “Guardar”. Cómo informamos a VFP que escriba el buffer al registro? Con buffering de registro, la tabla se actualiza cuando usted mueve el puntero del registro o usa la nueva función tableupdate(). Con buffering de tabla, moviendo el puntero del registro no actualiza la tabla (debido a que todo el punto del buffering de tabla es que varios registros son buffered al mismo tiempo), así la forma usual es llamar la función tableupdate(). Es mejor usar tableupdate() aún para buffering de registro debido a que usted tiene mas control sobre lo que sucede. tableupdate() devuelve .T. si el buffer se escribió con éxito al registro. Si el buffer de registro no ha cambiado (el usuario no ha editado algún campo, agregado un registro, o cambiado el estado de borrado para el registro), tableupdate() devuelve .T. pero no hace nada. tableupdate() puede recibir unos pocos parámetros opcionales: tableupdate(<AllRows>, <Forced>, <Alias> | <Workarea>) El primer parámetro indica qué registros actualizar: .F. informa que sólo se actualice el registro actual, mientras que .T. significa actualizar todos los registros (sólo tiene efecto si se usa buffering de tabla). Si el segundo parámetro es .T., cualquier cambio de otro usuario se sobre-escribirá por los cambios del usuario actual. A menos que se especifique el tercer parámetro, tableupdate() actualizará la tabla actual. Cómo cancelar los cambios que ha hecho el usuario? Con la estrategia de variables de memoria, usted sólo usa scatter memvar de nuevo para restaurar las variables de memoria a los valores almacenados en disco. Con buffering, use la función tablerevert() para realizar lo mismo para el buffer.
Magnifica información
ResponderBorrarMagnifica Información, Gracias...
ResponderBorrar