TRABAJAR CON TABLAS(DBF) DE FOXPRO 2 Y ADVANTAGE DATABASE SERVER

582 views
Skip to first unread message

Gerardo

unread,
Sep 30, 2014, 1:52:36 PM9/30/14
to mundovis...@googlegroups.com


Se me ha encomendado mover una aplicacion de fox 2.6 con tablas libres a una aplicacion de VFP conectada al Advantage Server (SQL), el driver del odbc de advantage me permite acceder a las tablas libres(dbf;) con el programa que estoy desarrollando en VFP, estas tablas son actualmente utilizadas por el programa de fox 2.6, tengo que hacer esta aplicacion mientras el programa viejo las sigue utilizando.  

El problema que tengo es que las tablas dbf no tienen campos autoincrementales,

Ejemplo de esto es una tabla en donde se guardan facturas, el FP2.6 usa la tabla ordenada por el campo factura
USE FACTURA ORDER FACTURA
muevo el puntero hasta  el ultimo registro
GO BOTT
**el programa le hace un lock al archivo
=FLOCK()
le incrementa un numero a la factura y la guarda en una variable
STORE FACTURA+1 TO FAC
graba el nuevo registro (hay otros campos que obvio)
replace factura with fac
y despues le quita el lock al archivo
UNLOCK

Este programa trabaja en un ambiente multiusuario, cuando yo accedo con VFP y Advantage, lo hago asi

me conecto con Advantage y guardo la conexion en una variable con
Loconn1="driver=Advantage StreamlineSQL ODBC;DataDirectory=\\SERVIDOR1\BARON3\REP1;DefaultType=Foxpro;ServerTypes=1;AdvantageLocking=OFF;uid='adssys';pwd=''"
STORE SQLSTRINGCONNECT(Loconn1) TO con

**busco el ultimo numero de factura con un select y lo guardo en un cursor FCURSOR
SQLEXEC(con,'Select MAX(FACTURA)  AS FACTURA  FROM FACTURA','FCURSOR')

**tomo del cursor la ultima factura y le incremento un numero
SELECT FCURSOR
STORE FACTURA+1 TO FAC

*guardo el comando insert en una variable sqlinsert
text to sqlinsert Textmerge Noshow Pretext 15
  insert into factura (factura) values (fac)
endtext

**mando los cambios al sql
SQLEXEC(con,sqlinsert)

Siento que en ambiente multiusuario esto me va a dar problemas, alguien ha tenido una experiencia similar?

Gracias

Gerardo

HernanCano

unread,
Oct 2, 2014, 12:59:20 AM10/2/14
to mundovis...@googlegroups.com
Gerardo.
Te voy ha hablar de tu método para obtener el consecutivo cuando programas en VFP:
Tienes un bug.

Me referiré al sgte código que tú mismo muestras:

USE FACTURA ORDER FACTURA
GO BOTT
=FLOCK()
STORE FACTURA+1 TO FAC

APPEND BLANK  && ésta línea no la muestras

REPLACE FACTURA WITH FAC
UNLOCK


Estás obteniendo el último consecutivo (con el STORE) que hay en el archivo.

Pero lo logras después de bloquear el archivo y posicionarse en el último registro.

Supongamos que hay al menos dos usuarios (al menos) accesando el mismo archivo DBF (Factura.dbf) y que ambos (o varios) intentan agregar un nuevo registro en el mismo instante. Alguno lo bloqueará primero. El segundo lo encontrará bloqueado y ---en el mejor de los casos--- tu comando FLOCK (en el orden en que los presentas) esperará a que sea desbloqueado (--en el mejor de los casos-- poniéndo ésto a tu favor).

Cuando el usuario actual se posicionó en el último registro encontró que era por ejm el 4545 (cuatro mil quinientos cuarenta y cinco). Pero como otro usuario lo tenía bloqueado, entonces esperó a que el otro usuario lo desbloqueara------
----- PERO EL OTRO USUARIO CUANDO LO DESBLOQUEA ya le agregó otro nuevo registro y lo grabó con el 4546-----

Entonces cuando el actual vaya a grabar también grabará con el 4546.... porque está parado en el 4545 y con el STORE captura que sigue el 4546, que será el que grabe.

---------------------------------
Te cuento que el sistema es bastante veloz y tal vez en 10 ó 20 ó 30 años nunca haya pasado.... ¿Pero qué hacer ante la duda?
¿Cuál sistema es veloz? El sistema es la combinación entre el sistema operativo, el lenguaje de programación, tu aplicación y la estructura de la red: lo más normal es que el script que tienes dure menos de 1 cienmilésima de segundo... Entonces ¿para qué preocuparse?
---------------------------------

¿Captaste el escenario de grabar consecutivo "doble"? Sorry if not.....

Solución:
Una posible mejora a tu código VFP para obtener el consecutivo es:

USE FACTURA ORDER FACTURA
=FLOCK()
GO BOTT
STORE FACTURA+1 TO FAC
APPEND BLANK  && ésta línea no la muestras
REPLACE FACTURA WITH FAC
UNLOCK

La clave de mi propuesta es "bloquear el archivo antes de ir al último registro".

Aunque me gusta más lo sgte:

USE FACTURA ORDER FACTURA
if FLOCK()
   GO BOTT
   STORE FACTURA+1 TO FAC
   APPEND BLANK  && ésta línea no la muestras
   REPLACE FACTURA WITH FAC
   UNLOCK
endif

Porque si el archivo no se bloquea, no puedes hacer APPEND ni REPLACEs.


Pregunta:
Sabemos que FLOCK() sólo intenta una sola vez si el registro puede ser bloqueado por mí (o sea por el usuario actual).
¿Qué pasa si no lo puede bloquear porque otro lo tiene bloqueado? R: no reintenta, sino que pasa al sgte comando, devolviendo falso (que significa: no se pudo bloquear).

Cuando el acceso es multiusuario --COMO ES EL CASO DE GERARDO, PUES ASI LO EXPRESA---, ¿no será evidente que la mayoría de las veces el archivo esté bloqueado por alguien más y por lo tanto se devuelva falso y no se pueda grabar el registro? ¿Deberemos usar SET REPROCES para que el reintento sea indefinido --¿infinito?--? o le PODEMOS decir al usuario 

=MessageBox('No se pudo grabar.'+chr(13)+'Vuelva a digitar sus datos dentro'+chr(13)+'de unos momentos, por favor',0,'FACTURAS')

¿Cierto?
Ambas alternativas son posibles....


Tip:
Para el Advantage, podrías hacer un procedimiento almacenado para grabar, ya que el lenguaje de programación es el mismo VFP y no necesitas aprender nuevos comandos ni instrucciones ni cláusulas.
(( aún no he conocido Advantage; supongo que acepta proc almacenados y con el lenguaje completo de VFP ))

---
Todo lo que te expongo aquí, lo hago de memoria, dada mi experiencia. No he ejecutado tus comandos ni mis propuestos, pues no lo considero necesario ni imperativo.

Sorry for long....

Gerardo Baron

unread,
Oct 2, 2014, 7:51:43 PM10/2/14
to mundovis...@googlegroups.com
Gracias Hernan, ese proceso lo ocupo cuando trabajo desde fox, pero esto es con sqlpassthru.  El problema lo arregle aqui esta un ejemplo como lo hice.

Use dos tablas una BB que guarda el detalle de la factura, tiene los campos CONTADOR(factura),NOMBRE Y DIRECCION, despues cree una tabla que lleva el contador de las facturas BBCOUNT solo tiene dos campos CONTADORBB, el cual lleva el ultimo numero de la factura y ENUSO, campo el cual marco cuando grabo, este campo me sirve para bloquear la tabla.  La conexion al servidor de Advantage esta guarda en la propiedad de la forma con, se hace referencia con "thisform.con"

Este programa lo probe con 3 computadoras grabando simultaneamente, y usando el programa viejo de fox 2.6, se grabaron 150 registros y nunca nos duplico, nos aviso cuando habia conflicto.  funciono perfectamente, eso quiere decir que el programa viejo de fox va a correr a la par del servidor Advantage SQL simultaneamente, esto me va a permitir migrar todo el programa a SQL usando el programa de fox 2.6 mientras escribo el nuevo ya cliente servidor.  
Gracias a los que me contestaron.

Slds.

Gerardo

***TOMA DE LAS FORMA LAS VARIABLES DEL NOMBRE Y DIRECCION, A LA VARIABLE "VAR" LE ASIGNA "SI"
STORE THISFORM.NOMBRE TO NOM
STORE THISFORM.DIREccion TO DIR
STORE "SI" TO VAR
***AQUI GUARDA EL COMANDO PARA VER SI LA TABLA DEL CONTADOR ESTA EN USO
Text To SSS4 Textmerge Noshow Pretext 15
  select CONTADORBB AS CONTADOR FROM BBCOUNT WHERE ENUSO<>'<<VAR>>'
ENDTEXT
*EJECUTA EL COMANDO PARA VER SI LA TABLA DEL CONTADOR ESTA EN USO
IF SQLEXEC(THISFORM.con,SSS4,'BBCOUNT2')<=0
  MESSAGEBOX("Hubo un Error, no se Pudo"+CHR(13)+"Traer la Tabla del Contador, Avise",48)
ELSE
  *SI TIENE EXITO EL CURSOR QUE GENERO "BBCOUNT2" SE REVISA PARA VER SI NO ESTA VACIO, SI ESTA      VACIO, QUIERE DECIR QUE LA TABLA ESTA EN USO
  SELECT BBCOUNT2
  GO TOP
  IF EOF()
    MESSAGEBOX("Alguien Esta Grabando un Registro o Hubo"+CHR(13)+ "un Problema Accediendo El Contador"+CHR(13)+ "de la Tabla",48)
    SELECT BBCOUNT2
    USE
    RETURN
  ENDIF
  **SI EL CURSOR NO ESTA VACIA, QUIERE DECIR QUE SE PUEDE CONTINUAR
ENDIF
**AQUI LE SUMA UN NUMERO AL CONTADOR DE LA TABLA BBCOUNT
SELECT BBCOUNT2
STORE CONTADOR+1 TO CONFINP
USE
**CREA EL COMANDO PARA BLOQUEAR LA TABLA BBCOUNT LA DEL CONTADOR
Text To SSS5 Textmerge Noshow Pretext 15
  UPDATE BBCOUNT SET ENUSO="<<VAR>>"
ENDTEXT
**BLOQUE LA TABLA PARA QUE NO SE PUEDA AGREGAR OTRO NUMERO
IF SQLEXEC(THISFORM.CON,SSS5)<=0
  =MESSAGEBOX("No se Pudo Bloquear La Tabla de Contador, Cancelara",48)
  return
ENDIF
*EJECUTA ESTE COMANDO POR SEGUNDA VEZ PARA VER SI LA TABLA DEL CONTADOR ESTA EN USO 
IF SQLEXEC(THISFORM.con,'SELECT CONTADORBB AS CONTADOR FROM BBCOUNT','BBCOUNT2')<=0
  MESSAGEBOX("Hubo un Error, no se Pudo"+CHR(13)+"Traer la Tabla del Contador, Avise",48)
ELSE
  *SI TIENE EXITO EL CURSOR QUE GENERO "BBCOUNT2" SE REVISA PARA VER SI NO ESTA VACIO, SI ESTA VACIO, QUIERE DECIR QUE LA TABLA ESTA EN USO
  SELECT BBCOUNT2
  GO TOP
  IF EOF()
    MESSAGEBOX("Alguien Esta Grabando un Registro o Hubo"+CHR(13)+ "un Problema Accediendo El Contador"+CHR(13)+ "de la Tabla",48)
    SELECT BBCOUNT2
    USE
    RETURN
  ENDIF
ENDIF
SELECT BBCOUNT2
STORE CONTADOR+1 TO CONFIN
**DE LAS DOS VARIABLES RESULTANTES DE LA CONSULTA SE VE SI SE HA CAMBIADO EL NUMERO, SI LO HIZO NO VA A GRABAR
IF CONFIN<>CONFINP
  MESSAGEBOX("Alguien Esta Grabando un Registro o Hubo"+CHR(13)+ "un Problema Accediendo El Contador"+CHR(13)+ "de la Tabla",48)
  **CREA EL COMANDO PARA SUMAR UN NUEVO REGISTRO A LA TABLA CONTADOR y DESBLOQUEA LA TABLA
  STORE "NO" TO VAR
  Text To SSS2 Textmerge Noshow Pretext 15
    UPDATE BBCOUNT SET ENUSO="<<VAR>>"
  ENDTEXT
  SQLEXEC(THISFORM.con,SSS2)
  RETURN
ENDIF
*CREA EL COMANDO PARA AGREGAR UN NUEVO REGISTRO
Text To SSS Textmerge Noshow Pretext 15
  INSERT INTO BB (NOMBRE,DIRECCION,CONTADOR) VALUES ("<<NOM>>","<<DIR>>",<<CONFIN>>)
ENDTEXT
**ENVIA EL COMANDO PARA GRABAR EL NUEVO REGISTRO
IF SQLEXEC(THISFORM.CON,SSS)<=0
  =MESSAGEBOX("No se Pudo Grabar el Registro, Avise, El Progama se Cancelara",48)
ENDIF
**CREA EL COMANDO PARA SUMAR UN NUEVO REGISTRO A LA TABLA CONTADOR y DESBLOQUEA LA TABLA
STORE "NO" TO VAR
Text To SSS2 Textmerge Noshow Pretext 15
  UPDATE BBCOUNT SET CONTADORBB=<<CONFIN>>,ENUSO="<<VAR>>"
ENDTEXT
**ENVIA EL NUEVO COMANDO PARA SUMAR UN NUEVO REGISTRO A LA TABLAA BBCOUNT (TABLA CONTADOR)
SQLEXEC(THISFORM.con,SSS2)
STORE CONFIN TO THISFORM.TXTCONTADOR.Value
THISFORM.Refresh



--
_______________________________________________________________
Has recibido este mensaje porque estás suscrito al Grupo "Mundo Visual
FoxPro" de Grupos de Google.
 
Para anular la suscripción a este grupo, envía un mensaje a:
mundovisualfox...@googlegroups.com
---
Has recibido este mensaje porque estás suscrito al grupo "Mundo Visual FoxPro" de Grupos de Google.
Para anular la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a mundovisualfox...@googlegroups.com.
Para acceder a más opciones, visita https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages