Otra forma
Si colocas en tus formularios las tablas en el entorno de datos ,todas se
manejan en modo exclusivo en .f. solo debes colocar en cada objeto tabla en
la propiedad bufferModeOverride en 5. Y cuando vayas a grabar :
SELECT Detalle
SET MULTILOCKS ON && Must be on for table buffering
= CURSORSETPROP('Buffering', 5, 'Detalle' ) && Enable table
buffering
= TABLEUPDATE(.T.) && Commits changes
-----Mensaje original-----
De: publice...@googlegroups.com
[mailto:publice...@googlegroups.com] En nombre de alfamaca
Enviado el: Jueves, 19 de Mayo de 2011 21:51
Para: Comunidad de Visual Foxpro en Español
Asunto: [vfp] Necesito usar tablas compartidas, en red!!
Tableupdate
(1362
palabras totales en este texto)
(8115 lecturas)
TableUpdate() en Visual FoxPro
por Jim Booth (Publicado originalmente en FoxTALK Mayo 1998)
Traducido por Roberto Alfredo Moré para PortalFox (http://www.portalfox.com)
TableUpdate() es una de las funciones usadas muy frecuentemente cuando se utiliza buffering en Visual FoxPro. La versión 5.0 de Visual FoxPro ha mejorado la funcionalidad de esta función. Este mes, examinaremos las mejoras a la función TableUpdate().
La sintaxis.
En Visual FoxPro versión 5 se ha mejorado la función TableUpdate(). Hay nuevas opciones que pueden usarse para hacer que esta función sea más útil a nosotros como desarrolladores. TableUpdate() tiene cuatro argumentos que controlan sus acciones. La siguiente es la sintaxis para la función TableUpdate.
TableUpdate( <nFilas>, <lForzar>, <cAliasTabla or nÁreaTrabajo>, <cMatrizErrores> )
nFilas.
Miremos cada uno de los argumentos de esta función. El primer argumento controla como la función trabajará con múltiples registros en el buffer. Este es probablemente el argumento más confuso de la función.
nFilas aceptará uno de los tres valores 0, 1, o 2. Un valor de 0 sólo actualizará el registro actual independientemente si el buffering es tabla o fila. Este argumento puede ser usado para controlar la edición de un único registro cuando se usa buffering de tabla o para procesar cada registro en el buffer separadamente.
Un valor de 1 actualizará todos los registros en el buffer en una llamada a TableUpdate. Si TableUpdate encuentra un registro que no puede ser actualizado, fallará en ese punto y retornará un valor de .F., indicando que ha fallado. Ningún registro más allá del que tiene el problema será procesado.
Usando 2 como valor de nFilas también actualiza todos los registros en una llamada a la función, pero reacciona diferentemente si falla en un registro. Si un registro no puede ser actualizado, continuará con el resto de los registros y actualizará todos los que pueda. TableUpdate retornará un valor .F. indicando que hubo un problema y llenará la matriz referenciada en el cuarto argumento con los registros que no pudo actualizar.
Si no se define un valor para nFilas se usa el valor 0.
lForzar.
El segundo argumento es un valor lógico .T. o .F. y controla como TableUpdate tratará los conflictos cuando otro usuario haya cambiado el registro mientras estábamos trabajando sobre él. Un valor de .T. forzará nuestra actualización y sobrescribirá los cambios realizados por el otro usuario, mientras que un valor de .F. no realizará la actualización si otro usuario ha hecho modificaciones al mismo registro.
Es una buena idea usar .F. para este argumento, ya que el sobrescribir los cambios de otros usuarios puede producir resultados no deseados en la tabla. Siempre podemos escribir código de recuperación para un TableUpdate fallido que pueda rectificar las diferencias y luego forzar una actualización (discutiremos este tipo de código el próximo mes).
cAliasTabla/nÁreaTrabajo
Este argumento es usado para determinar qué área de trabajo o alias será afectado por el llamado a la función TableUpdate. Si se omite este argumento, se afecta el área de trabajo actualmente seleccionada. Se recomienda que siempre se indique el nombre de alias a la función TableUpdate() para prevenir resultados inesperados. En Visual FoxPro es muy fácil encontrarse con un área de trabajo cambiada y mediante el uso de este argumento no quedará ninguna duda sobre que área de trabajo debe ser actualizada.
cMatrizErrores
Este argumento es el nombre de una matriz unidimensional que contendrá los números de registro de aquellos registros que no hayan podido actualizarse cuando se usa como valor del primer argumento 2. Este argumento debería indicarse siempre cuando se usa un valor de 2 para el primer argumento, ya que no hay otra manera de averiguar cuáles son los registros no actualizados.
Cuando el primer argumento es 0 o 1 el puntero de registro en el alias que está siendo actualizado permanece en el registro que no pudo actualizarse. f
Muéstranos algo de código.
Con todas estas opciones en la función, habría varias maneras de utilizarla en nuestro código. Examinemos algunos escenarios.
Escenario 1 – Actualización de un registro único.
Tenemos un formulario que permite la edición de sólo un registro de cliente y está usando solamente la tabla de clientes (Customer). El código que podríamos tener en el método de grabado de este formulario se muestra en el Listado 2.
LOCAL lcFldState
lcFldState = GetFldState( -1,”Customer”)
IF “2” $ lcFldState OR “4” $ lcFldState
* Se ha editado un registro existente o bien uno nuevo.
IF NOT TableUpdate( 0, .F., “Customer” )
* The update failed
TableRevert(.F., “Customer”)
ENDIF
ENDIF
Listado 2 – Un ejemplo de actualización de un registro único.
Escenario 2 – Múltiples registros, todos o ninguno.
En esta situación tenemos un formulario para editar clientes que permite al usuario editar varios registros de clientes antes de guardar el trabajo. Deseamos guardar todas las ediciones o no guardar ninguna.
* Se ha editado un registro existente o bien uno nuevo.
BEGIN TRANSACTION
IF NOT TableUpdate( 1, .F., “Customer” )
* The update failed
ROLLBACK
TableRevert(.T., “Customer”)
ELSE
END TRANSACTION
ENDIF
Listado 3 – Actualizando múltiples registros usando 1 como primer argumento de TableUpdate()
Escenario 3 – Múltiples registros, haga lo que pueda.
En este ejemplo tenemos la misma situación de edición que en el Escenario 2, pero deseamos guardar todo lo que podamos y revertir únicamente los registros que no puedan ser guardados.
* Se ha editado un registro existente o bien uno nuevo.
DIMENSION laBadRecs(1)
IF NOT TableUpdate( 2, .F., “Customer”, laBadRecs )
* The update failed
FOR EACH nRecord IN laBadRecs
GOTO nRecord
TableRevert(.F., “Customer”)
ENDFOR
ENDIF
Listado 4 – Actualizando múltiples registros usando 2 como el primer argumento de TableUpdate()
En resumen.
La función TableRevert() fue usada en cada uno de los ejemplos. Esta función toma dos argumentos. El primero es .T. para revertir todos los registros y .F. para revertir sólo el registro actual. El segundo argumento es el alias a ser revertido.
En el segundo escenario, se usó una transacción para englobar toda la actualización en una operación de o todo o nada. Las transacciones serán el tema de otra publicación.
Las mejoras a la función TableUpdate nos dan un control muy fino sobre la forma de trabajar de la operación de actualización. Como usted puede ver en los ejemplos, podemos controlar la actualización de nuestras tablas de forma de lograr el comportamiento exacto que deseamos para cada uno de los formularios que construyamos.
Transacciones
(1543
palabras totales en este texto)
(7635 lecturas)
Publicado originalmente en FoxTALK en Junio de 1998
Usando Transacciones
Jim Booth
Traducido por Pablo Roc Serrano para PortalFox (http://www.portalfox.com)
Previamente habíamos hablado sobre TableUpdate y TableRevert() y hemos visto como nos permiten controlar actualizaciones mientras usamos "buffering" en tablas y cursores. Estas dos opciones son muy buenas para manejar la actualización o la reversión de una sóla tabla o cursor, pero cómo coordinamos las actualizaciones o cancelaciones de varias tablas relacionadas. Aquí entran las Transacciones.
Pero, ¿qué es una transacción?
Hay situaciones en las que necesitamos actualizar más de una tabla o cursor y la combinación de actualizaciones representa una de las acciones en la Base de Datos. Esta acción debería ser una operación "todo o nada", es decir, Todo si todo va bien o Nada si algo falla. Por ejemplo, cuando escribimos código para guardar una nueva factura tenemos que añadir un registro en la tabla de cabecera de facturas, añadir un grupo de registros en la tabla de líneas de factura, modificar el saldo en el registro del cliente ya añadir un registro en la tabla de recibos. Si alguna de estas operaciones falla necesitamos deshacer todas las operaciones anteriores que sí han funcionado y asegurarnos que no se han realizado cambios en los datos. Las transacciones se han diseñado para este propósito.
Utilizaremos la instrucción BEGIN TRANSACTION para comenzar el seguimiento de la transacción en Visual FoxPro y la instrucción ENDTRANSACTION para terminar correctamente la transacción o la intrucción ROLLBACK para deshacer la transacción.
¿Cómo funcionan las transacciones?
Cuando VFP encuentra un BEGIN TRANSACTION comienza a hacer un seguimiento de las operaciones de actualización de fichero que se realizan. Para cada modificación VFP obtiene los bloquedos adecuados pero no realiza la actualización todavía. Cuando encuentra un ENDTRANSACTION Visual FoxPro realiza todas las escrituras de fichero involucradas en la transacción y libera los bloqueos que se había procurado con anterioridad. Si encuenta un ROLLBACK, Visual FoxPro abandona los bloqueos sin realizar ninguna operación de escritura.
Gracias a este proceso, Visual FoxPro es capaz de asegurar que todos los cambios se realizarán o no se realizará ninguno. Como podemos apreciar examinando este proceso es una muy buena idea poner las instrucciones BEGIN TRANSACTION y ENDTRANSACTION/ROLLBACK lo más cerca posible una de otra en el código como sea posible. Haciendo esto reduciremos el tiempo en el que los recursos están bloqueados.
¿Qué tablas y cursores pueden participar en una transacción?
En Visual FoxPro las transacciones sólo están disponibles para tablas que están en Bases de Datos (DBC). Las tablas libres no pueden participar en una transacción, y un rollback (roll back es literalmente "enrollar") u otro final anormal de una transacción no afecta a las modificaciones realizadas sobre tablas libres durante una transacción.
Esto puede causar efectos sorprendentes si una tabla libre es la fuente de datos de una tabla local que es gestionada por una transacción. Vamos a examinar los pasos del proceso con una transacción ficticia. En esta transacción hay una tabla perteneciente a una Base de Datos que se llama Tabla1 y una vista llamada Vista1 que consigue los datos de una tabla libre que se llama (originalidad sin fronteras) Tabla2. El código para la transacción es el que sigue:
BEGIN TRANSACTION
IF TableUpdate( 1, .F., "Vista1")
IF TableUpdate ( 1, .F., "Tabla1")
END TRANSACTION
ELSE
ROLLBACK
ENDIF
ELSE
ROLLBACK
ENDIF
Ahora las preguntas, si el TableUpdata de Tabla1 falla, ¿puede el ROLLBACK deshacer los cambios de Vista1 y dejarla en el estado anterior a la transacción? La respuesta es sí, puede deshacer los cambios en Vista1. ¿Pueden los cambios hechos en Table2 como resultado de la actualización de Vista1 ser deshechos por el ROLLBACK? No, porque Tabla2 es una tabla libre y, como tal, no participa en la transacción. Esto puede dejar tus datos en un estado inconsistente, deberías manejar la tabla libre por ti mismo. Lo mejor en no depender de transacciones cuando estén relacionadas tablas libres.
¡Enséñanos el código!
¿Cómo integraremos transacciones en nuestros formularios? Se puede hacer en un formulario directamente o genéricamente en una clase de formularios. Debajo hay un pseudocódigo que nos dará una idea de cómo es la estructura para incorporar transacciones en nuestras actualizaciones.
* Establecer una variable para el seguimiento de fallos
LOCAL llRollBack
llRollBack = .F.
* Esperar hasta que todo el proceso de datos está completo antes de comenzar la
transacción
BEGIN TRANSACTION
* Realizar cada actualización comprobando el resultado
IF NOT TableUpdate( ... )
llRollBack = .T.
ELSE
IF NOT TableUpdate( ... )
llRollBack = .T.
ELSE
IF NOT TableUpdate( ... )
llRollBack = .T.
ENDIF
ENDIF
ENDIF
IF llRollBack
ROLLBACK
ELSE
ENDTRANSACTION
ENDIF
Este código de arriba es pseudocódigo, no lo tomes al pie de la letra. Hemos usado una serie de instrucciones IF anidadas para controlar las acciones. Podríamos haber puesto todos los alias en una matriz y utilizar un bulce FOR/ENDFOR para procesarlos, terminando el bucle cuando hubiera un error o termináramos con todos.
¿Qué puede ir mal?
En el pseudocódigo de arriba asumimos que la transacción falla y que se se ha realizado el ROLLBACK. ¿Qué, exactamente, ha hecho el ROLLBACK? ¿Los "buffers" se han dejado en su estado pre-edición o todavía tienen basura de la edición del usuario?
La respuesta es que los "buffers" se restauran al estado en el que estaban antes del BEGIN TRANSACTION. Esto quiere decir que todavía tenemos que ocuparnos de la edición del usuario. Aquí nosotros decidimos, podemos poner lo editado por el usuario de nuevo en el formulario y dejarle decidir a él, o podemos realizar un TableRevert con todos los alias y descartar lo que ha escrito el usuario. El límite lo ponemos nosotros.
¿Qué ocurre si el ordenador se apaga (o cuelga) durante la transacción? Obviamente VFP no tiene registro de la transacción cuando el sistema es reiniciado. Entonces ¿las tablas se han actualizado o no? Ninguna tabla se modificó y el resultado es como se hubiera ejecutado un ROLLBACK.
Otra situación que puede ocurrir y causar muchos problemas es esta, un desarrollador escribe un formulario y pone un BEGIN TRANSACTION en el evento Init y pone un ENDTRANSACTION o un ROLLBACK en el evento destroy, dependiendo del botón que pulse el usuario para salir del formulario. ¿Qué problema puede causar esto? En primer lugar ningún otro usuario puede hacer nada con las tablas implicadas en la transacción mientras tanto, hasta que el usuario sale del formulario y se eliminan los bloqueos. He visto esta situación usada como argumento contra las transacciones. Bueno, vamos allá, cualquier cosa que se utiliza incorrectamente puede causar problemas. Cuando se usan transacciones correctamente se limitará el tiempo entre el comienzo y el final al mínimo imprescindible. Los eventos Init y Destroy de un formulario NO son el menor periodo de tiempo posible. Este periodo de tiempo no está nunca bajo el control del programador.
He visto escrito que las transacciones de Visual FoxPro no son tan "robustas" como las transacciones que utilizan los servidores de bases de datos cliente/servidor. ¿Y qué?. De hecho, los frenos de un tractor son más "robustos" que los frenos de mi coche, ¿ es eso una razón para NO usar los frenos de mi coche? NO. Las transacciones de Visual FoxPro son útiles y sirven para su propósito. Se deben utilizar, incluso cuando los datos están almacenados en un Base de Datos cliente/servidor.
Resumen
Las transacciones de Visual FoxPro son una utilidad muy valiosa del producto. Nos permiten agrupar varias operaciones de actualización en una operación "todo o nada". Hoy por hoy raramente creamos formularios que sólo gestionan una tabla, el formulario con múltiples tabla se ha convertido en una norma. Gestionar estas actualizaciones de varias tablas se ha convertido en un aspecto muy importante de nuestro trabajo y las transacciones tienen un valor inestimable para hacerlo.
Amigo Cristopher:
Estas usando el SET EXCLUSIVE en estado OFF?
Buen día.
Carlos Alfaro
Hola, si lo eh intentado usar, pero con él o sin él, no me permite abrir las tablas en más de un equipo. No sé cómo deba de hacerlo, mira. yo tengo 3 pc, en una puse las tablas libres que ocupo ( si es necesario lo hago con base de datos si me lo recomiendan) la carpeta dónde están esas tablas la comparto , y en los otros dos equipos les conecto una unidad de red con ubicación de esa carpeta de la pc donde están las tablas, y en las otras dos pc creo un programa en el cual a la hora de llamar a la tabla, le doy la ubicación de la unidad de red, y si acceden a la tabla, pero solo puedo tener acceso un ordenador a la vez. No sé si me explique bien, espero me puedan ayudar con mi problemática.
Insisto:Si has usado SET EXCLUSIVE OFF y estuvieras abriendo las DBFs con USE ARCHIVO, o con USE ARCHIVO SHARED, no se te presentaría el mensaje.
Hola, si lo eh intentado usar, pero con él o sin él, no me permite abrir las tablas en más de un equipo. No sé cómo deba de hacerlo, mira. yo tengo 3 pc, en una puse las tablas libres que ocupo ( si es necesario lo hago con base de datos si me lo recomiendan) la carpeta dónde están esas tablas la comparto , y en los otros dos equipos les conecto una unidad de red con ubicación de esa carpeta de la pc donde están las tablas, y en las otras dos pc creo un programa en el cual a la hora de llamar a la tabla, le doy la ubicación de la unidad de red, y si acceden a la tabla, pero solo puedo tener acceso un ordenador a la vez. No sé si me explique bien, espero me puedan ayudar con mi problemática.
Amigo Cristopher:
Para trabajar en red TODAS tus tablas tienen que estar compartidas. La única excepción es cuando tienes tablas locales en cada computadora, esas sí pueden tener acceso exclusivo, pero las tablas a las cuales accederán varios usuarios deben estar compartidas. Para compartirlas puedes hacer de dos formas:
1. Escribir SET EXCLUSIVE OFF antes de abrir tus tablas, o
2. Cada vez que abres una tabla le pones USE MiTabla SHARED
La opción 1. es la recomendable.
Saludos.
Walter.
> Date: Thu, 19 May 2011 19:51:16 -0700
> Subject: [vfp] Necesito usar tablas compartidas, en red!!
> From: alfam...@yahoo.com
Tenes que abrirla en modo EXCLUSIVO
Por ende tenes que preguntar primero si la tabla esta en uso
Si no lo esta
Set Excl On
Abris la tabla
ZAP
Cerras la tabla
Set excl OFF
Listo
Arnaldo Toledano
El 15/06/2015 a las 11:07 a.m., Cristopher Antonio A.G escibió:
hola, y como puedo aplicarle un zap o algo similar, a una tabla compartida ?
El jueves, 19 de mayo de 2011, 21:32:44 (UTC-6), Walter R. Ojeda Valiente escribió:
Para trabajar en red TODAS tus tablas tienen que estar compartidas. La única excepción es cuando tienes tablas locales en cada computadora, esas sí pueden tener acceso exclusivo, pero las tablas a las cuales accederán varios usuarios deben estar compartidas. Para compartirlas puedes hacer de dos formas:
1. Escribir SET EXCLUSIVE OFF antes de abrir tus tablas, o
2. Cada vez que abres una tabla le pones USE MiTabla SHARED
La opción 1. es la recomendable.
Saludos.
Walter.
> Date: Thu, 19 May 2011 19:51:16 -0700
> Subject: [vfp] Necesito usar tablas compartidas, en red!!
> From: alfam...@yahoo.com
>
> Hola a todos! Tengo que entregar un sistema que funcione en red para 8
> personas, todos pueden acceder a la informaciòn de las tabla a la vez!
> "Como hago para usar tablas compartidas en vfp 9.0 con el s.o windows
> 7??" yo uso lo siguiente: if not used("tabla.dbf")
> use tabla shared
> else
> select tabla
> endif
> Pero me dijeron que esto no sirve en el vfp 9.0, por favor, esto me
> tiene desesperado! necesito su ayuda!
Mi comentario no es para resolver tu problema.
Me llama la atención que estuviste preguntando, cómo hacer para una tabla pudiera ser accesible por más de una computadora y ahora necesitas aplicar zap a una tabla.
Podrás aplicar zap a esa tabla, abriéndola con el comando exclusive, por ejemplo:
Use mitabla exclusive
Pero toma en cuenta que no podrá ser accedida por más de una computadora.
Buen dia.
Carlos Alfaro
Revisa bien, porque toda tabla abierta en modo exclusive se puede aplicar zap.
Debo suponer que en use mitabla exclusive, sustituis mitabla por el nombre de la tabla que necesitas aplicar zap.
Ups, bueno. me voy con la cabeza hagachada y avergonzado...je,je,je
Saludos!!!
Es un pre-viernes...ja,ja,ja
Lo que pasa amigo Fernando, es que el amigo Cristopher, tomo este hilo y expuso su consulta el 15 del presente mes.
Buen dia.
Carlos Alfaro