Sí, sigue siendo crítico. La estructura y manejo de DBFs no ha cambiado.
Desde Clipper con DOS he trabajado unas rutinas que han mejorado con el tiempo y ahora tambien me sirven para manejar tablas SQL.
Acostumbro a abrir todas las tablas de control una sola vez, entre ellas las que me sirven para controlar parámetros, procesos, actividades, permisos, usuarios, mensajes, etc. estas tablas se encuentran en la carpeta principal y en el caso de SQL forman una base de datos.
Los tablas de trabajo pueden encontrarse en otras carpetas o para el caso de SQL formar otra base de datos, estas tablas las abro y cierro de acuerdo a las necesidades, normalmente son abiertas al ingresar al programa o paso que las requiera y cerradas al finalizar.
La misma tabla puede ser abierta n veces sin problema, talvez el secreto esté en el uso y manejo del ALIAS.
He aquí el código:
- Code: Select all Expand view
STATIC aDbfs:={}
/*
cAlias:=Open_Dbf("MiTabla")
...
(cAlias)->(DbAppend())
(cAlias)->DatoN:=cData
(cAlias)->(DBCommit())
(cAlias)->(DbUnlock())
...
Close_Dbf("MiTabla",cAlias)
*/
// --- Apertura y cierre de tablas DBF, SQL (totalmente MDI)
FUNCTION Open_Dbf(cDbf,lDat,lShr)
LOCAL cDriver:=DbSetDriver()
LOCAL nI, nD, cAlias, oDbf
LOCAL cFile, cRut
DEFAULT lDat:=.T.
DEFAULT lShr:=.T.
CursorWait()
IF cDriver="DBFCDX"
cRut:=IF(lDat,cPatD,cPath)
ELSE
IF lDat
SR_SetActiveConnection(nData)
ELSE
SR_SetActiveConnection(nMain)
ENDIF
ENDIF
IF Select(cDbf)>0
DBSelectArea(cDbf)
nD:=AScan(aDbfs,{|aAt| aAt[1]==cDbf})
IF nD>0
aDbfs[nD,2]++
ENDIF
cAlias:=New_Alias(cDbf,nD)
cFile :=IF(cDriver="DBFCDX",cRut+Upper(cDbf),cDbf+".DBF")
DbUseArea(.T.,cDriver,cFile,cAlias,lShr,.F.)
IF !Empty(OrdName(1))
(cAlias)->(DbSetIndex(cFile))
(cAlias)->(OrdSetFocus(1))
ENDIF
ELSE
nD:=AScan(aDbfs,{|aAt| aAt[1]==cDbf})
IF nD=0
AAdd(aDbfs,{cDbf,1})
nD:=AScan(aDbfs,{|aAt| aAt[1]==cDbf})
ELSE
aDbfs[nD,2]++
ENDIF
cAlias:=New_Alias(cDbf,nD)
cFile :=IF(cDriver="DBFCDX",cRut+Upper(cDbf),cDbf+".DBF")
DbUseArea(.T.,cDriver,cFile,cAlias,lShr,.F.)
IF !Empty(OrdName(1))
(cAlias)->(DbSetIndex(cFile))
(cAlias)->(OrdSetFocus(1))
ENDIF
ENDIF
CursorArrow()
RETURN (cAlias)
STAT FUNC New_Alias(cDbf,nD)
LOCAL cAlias, cX, nX:=0
IF Select(cDbf)=0
RETURN (cDbf)
ENDIF
cX:=LTrim(Str(aDbfs[nD,2]-1))
cAlias:=cDbf+cX
DO WHILE Select(cAlias)>0
nX:=Val(cX)+1
cX:=LTrim(Str(nX))
cAlias:=cDbf+cX
ENDDO
RETURN (cAlias)
FUNCTION Close_Dbf(cDbf,cAlias,lEnd)
LOCAL nD
DEFAULT lEnd:=.F.
DEFAULT cAlias:=cDbf
CursorWait()
cDbf:=Upper(cDbf)
IF Select(cDbf)>0
nD:=AScan(aDbfs,{|aAt| aAt[1]==cDbf})
IF nD>0
IF lEnd
IF Select(cAlias)>0
(cAlias)->(DbCloseArea())
ENDIF
IF Select(cDbf)>0
Close(cDbf)
ENDIF
aDbfs[nD,2]:=0
ELSE
IF aDbfs[nD,2]>0
aDbfs[nD,2]--
IF Select(cAlias)>0
(cAlias)->(DbCloseArea())
ENDIF
ENDIF
ENDIF
ENDIF
ELSE
nD:=AScan(aDbfs,{|aAt| aAt[1]==cDbf})
IF nD>0
aDbfs[nD,2]:=0
ENDIF
ENDIF
CursorArrow()
RETURN (NIL)
FUNCTION Verif_Close() // Verifica si quedan tablas abiertas, útil durante el desarrollo
LOCAL nD
FOR nD=1 TO Len(aDbfs)
IF aDbfs[nD,2]>0
MsgInfo("Falto por cerrar "+aDbfs[nD,1]+Tran(aDbfs[nD,2],"999"))
ENDIF
NEXT nD
RETURN (NIL)