Gravando no banco de dados do Clipper em modo multiusuário. Observe os comentário no exemplo abaixo.
// Abre arquivo CLIENTE (banco de dados) e o apelida como 'CLI'. // Toda vez que tiver um 'CLI->' se refere a um campo do arquivo CLIENTE // ou função que rode como se desse um SELECT CLIENTE 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 que insere um registro em branco 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) // se não existir o arquivo nHandle := FCREATE(ARQUIVO, 0) // então, cria o arquivo IF FERROR() # 0 ALERT("Erro"+ALLTRIM(STR( FERROR() ))+": Arquivo não pode ser criado!!!" ) QUIT ELSE // deu certo! arquivo criado em branco. FWRITE(nHandle, "000000") // grava 000000 no arquivo. O código irá até 999999. FCLOSE(nHandle) // fecha arquivo ENDIF ENDIF nHandle := FOPEN(ARQUIVO, 66) // abre arquivo IF FERROR() != 0 ALERT("Erro"+ALLTRIM(STR( FERROR() ))+": Arquivo não pode ser aberto!!" ) QUIT ENDIF nCOD := VAL( FREADSTR(nHANDLE, 6) ) // lê o arquivo e armazena o conteúdo dele em nCOD nCOD++ // acrescenta +1 FSEEK(nHANDLE, 0) FWRITE(nHANDLE, STRZERO(nCOD,6)) // grava novo código no arquivo FCLOSE(nHANDLE) // fecha o arquivo 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.
Comentários recentes