Gravando dados

Gravando dados


A seguir será mostrado um exemplo.

// o (//) é comentário
// Abertura de arquivo
USE CLIENTE ALIAS CLI SHARED NEW
SET INDEX TO CODCLI
// Definicao de variaveis
// técnica: letra inicial da variavel igual ao tipo da variavel: c = caracter
cNOME := SPACE(30)
cEND := SPACE(35)
CLS
@ 10,10 SAY "Nome:" GET cNOME
@ 11,10 SAY "Endereço:" GET cEND
READ
nCOD := NOVOCOD("CODCLI.DAT") // Falarei mais detalhadamente mais adiante
// a chamada ao DBAPPEND() ou ao APPEND BLANK já faz um bloqueio
// automatico no registro, sendo desnecessario a nossa função BLOQREG() (tópico 1)
// até porque, se não fosse, o clipper retornaria um erro.
CLI->(DBAPPEND()) // Função de Append Blank no arquivo CLIENTE (apelidado CLI), veja uma observacao no final.
// Note como são referenciados as variaveis do arquivo: alias->campo do arquivo
CLI->NOME := cNOME
CLI->ENDERECO := cEND
CLI->CODIGO := nCOD
CLI->(DBUNLOCK()) // libera o registro p/ uso
CLI->(DBCOMMIT()) // assegura a integridade do DBF
...
FUNCTION NOVOCOD(ARQUIVO)
IF !FILE(ARQUIVO)
   nHandle := FCREATE(ARQUIVO, 0)
   IF FERROR() # 0
      ALERT("Erro"+ALLTRIM(STR( FERROR() ))+": Arquivo não pode ser criado!!!" )
      QUIT
   ELSE
      FWRITE(nHandle, "000000")
      FCLOSE(nHandle)
 __ENDIF
ENDIF
nHandle := FOPEN(ARQUIVO, 66)
IF FERROR() != 0
   ALERT("Erro"+ALLTRIM(STR( FERROR() ))+": Arquivo não pode ser aberto!!" )
   QUIT
ENDIF
nCOD := VAL( FREADSTR(nHANDLE, 6) )
nCOD++
FSEEK(nHANDLE, 0)     
FWRITE(nHANDLE, STRZERO(nCOD,6))
FCLOSE(nHANDLE)
RETURN (nCOD)

Assim deverá ser a rotina de gravação de um arquivo em modo compartilhado. Agora vamos a algumas observações.

nCOD := NOVOCOD("CODCLI.DAT"))

Os arquivos DBF em rede tem problema de integridade, que devem ser minimizados com medidas de segurança por parte do programador. Refiro-me a integridade dos arquivos de índice principalmente. Já pensou se você atribuisse o novo código desta forma:
 
CLI->(DBGOBOTTOM())
nCOD := CLI->CODIGO + 1

E o seu arquivo de indice estivesse corrompido??? Geraria um código repetidos e comprometeria a consistência do arquivo, que teria dois códigos iguais.

Mas e se você fizesse assim:

nCOD := CLI->(LASTREC()) +1

E quisesse excluir algum registro??? Também não daria certo!

O melhor então é criar um arquivo separado, de texto, que guarde o valor do código atual, para que a chamada da nossa função retorne o novo código, como foi feito na função NOVOCOD().

Observação: Caso você precise de vários DBF's com um campo de código p/ chave primária, uma outra solução é criar uma base de dados com apenas um registro e, vários campos, um campo para armazenar o código atual de cada chave primária do seu sistema. Assim, toda vez que for incluir um registro, você abre a base de dados com as chaves, bloqueia o registro, pega o valor da chave que você quer, soma +1 (mais um), atualiza o campo com o valor da chave atual, desbloqueia o registro e usa este último valor como a chave para o código. Se, no entanto esta base tiver muitos campos, seu sistema provavelmente utilizará muito a base e alguém pode encontrar seu único registro bloqueado por tempo considerado.

 

Append Blank/DbAppend()

Se você possui no seu sistema um programa em que a inclusão de registros é muito grande em rede, tipo registro de vendas, crie uma função para incluir um registro em branco, tratando o erro, pois um Append Blank/DbAppend() falhará se outro usuário tiver bloqueado o banco de dados ou estiver tentando incluir um registro ao mesmo tempo! Veja como ficaria:

CLI->(APPEND()) // Função para o Append Blank no arquivo CLIENTE (apelidado CLI), chamando a função desta forma você já seleciona o arquivo de alias CLI para a função trabalhar.
...
FUNCTION APPEND()
DBAPPEND()
DO WHILE NETERR() // Se falhou de novo, fica tentando...
   DBAPPEND()
ENDDO
RETURN

Outra observação importante: Não adianta tentar bloquear o registro (Rlock()) ou usar sua função de bloqueio de registro antes do DbAppend(), pois estaríamos bloqueando o registro corrente e estamos, na verdade, tentando incluir um novo registro pelo sistema, destarte, é apropriada apenas o exemplo acima.