Função de Autonumeração( Uso Geral )

Aqui você poderá oferecer suas Contribuições, Dicas e Tutoriais (Texto ou Vídeo) que sejam de interesse de todos.

Moderador: Moderadores

Avatar do usuário
rochinha
Administrador
Administrador
Mensagens: 4664
Registrado em: 18 Ago 2003 20:43
Localização: São Paulo - Brasil
Contato:

Função de Autonumeração( Uso Geral )

Mensagem por rochinha »

Amiguinhos

A função que apresento é muito boa para se controlar os vários contadores que usamos em nossos sistemas e vale a pena investir em seu uso, já que a velha técnica de pegar o RECNO() sempre falha após um exclusão fisica via PACK.

Exemplo:

Eu tinha um cadastro de clientes com 20 registros e eliminei 5 aleatóriamente ficando com 15. Ao usar um PACK o meu RECNO()+1 devolveria 16 e se usasse este numero eu poderia ter registros duplicados.

A função possui um cálculo que retorna um valor baseado na regra:

nControle := ... recco()+(recco()/2) ...

Ou seja numero de registros é igual ao seu total mais sua metade, ou seja, meu proximo contador poderia ser 22 ou 23.

Ela não é a prova de falhas, pois depende de um cálculo FIXO baseado em valores FLUTUANTES.

Seu código é:

Código: Selecionar todos

FUNCTION PsqControle( database )
   // Inicializa controle com um numero diferente do total de registros
   nControle := iif( recco()=0, 1, recco()+(recco()/2) )
   // Guarda a área atual do .DBf a ser controlado
   OldArea := Select()
   If !File("CONTROLE.DBF")
      // Cria a estrutura do controlador caso ainda não exista
      ESTRU_DBF := { ;
           { "DATABASE"  , "C",12, 0 } , ;  // Guarda o nome do DBF/ALIAS
           { "CONTADOR"  , "N", 7, 0 } }    // Armazena o contador
            DBCREATE( "CONTROLE", ESTRU_DBF )
   EndIf
   If Select("CONTROLE") == 0 // Se ainda não estiver aberto, abre...
      USE controle NEW
   Else
      DbSelectar("CONTROLE")  // Se ja estiver aberto SELEciona
   EndIf
   // Verifica a existencia da chave( que pode ser também uma palavra )
   LOCATE FOR UPPER(controle->database) = UPPER(database)
   if found()
      // Encontrando incrementa o contador
      nControle := controle->contador + 1
      RLOCK() // Usado no caso de rede
      controle->contador := nControle
      COMMIT
   else
      // Caso a chave ainda não exista será criada
      APPEND BLANK
      controle->database := database
      controle->contador := nControle
      COMMIT
   endif
   // Volta a área antiga
   SELE (OldArea)
   // Retorna o numero de controle
   RETURN nControle
O seu uso é muito simples:

...
CLIENTES->IDCLIENTE := PsqControle( DBF() )
APPEND BLANK
...
COMMIT
...

O registro de cliente será salvo com um numero atualizado e o controle também será atualizado.

A manutenção do arquivo de controle poderá ser feita também via dBase, DBU ,Fox ou um browse interno chamado pelos menos de sua aplicação .

@braços :xau
Editado pela última vez por rochinha em 29 Set 2006 10:56, em um total de 1 vez.
gavel
Usuário Nível 1
Usuário Nível 1
Mensagens: 39
Registrado em: 16 Mar 2005 07:30

Contador

Mensagem por gavel »

Eu uso o contador do MIRO. é muito interessante, quando em rede, pois ele evita um cadastro duplo do mesmo código para clientes diferentes.
Mesmo assim ele comete falha. Por isso eu implementei um pouco.

Ex.: 2 computadores abrem um cadastro de cliente e buscam o ultimo registro. O contador do banco de dados não sabe se outro terminal está cadastrando um novo código.
O que fiz? criei um contador temporário de cada código criado num intervalo de milésimos de segundo, para cada terminal. Assim nunca nenhum deles irá repetir o mesmo número. seria algo como dois carros de fórmula 1 passar na linha de chegada no mesmo milésimo.

hehehe :))
Abraços.
Gavel
Avatar do usuário
rochinha
Administrador
Administrador
Mensagens: 4664
Registrado em: 18 Ago 2003 20:43
Localização: São Paulo - Brasil
Contato:

Mensagem por rochinha »

Amiguinho

Isto pode ser resolvido com a seguinte modificação:

Antes:

FUNCTION PsqControle( database )
...
LOCATE FOR UPPER(controle->database) = UPPER(database)
if found()
// Encontrando incrementa o contador
nControle := controle->contador + 1
RLOCK() // Usado no caso de rede

controle->contador := nControle
COMMIT
...
RETURN nControle

Depois:

FUNCTION PsqControle( database )
...
LOCATE FOR UPPER(controle->database) = UPPER(database)
if found()
// Encontrando incrementa o contador
RLOCK() // Usado no caso de rede
nControle := controle->contador + 1

controle->contador := nControle
COMMIT
...
RETURN nControle

Desta forma o numero de cadastro será retornado a primeira estação e liberado após o destravamento sendo impossivel antes do travamento que duas estações possuam o mesmo código.

O motivo da criação desta função é que quando usamos numeradores baseados no numero de registro de um .dBF, ou recco() os mesmos falhas quando executamos PACKs. Portanto existe a necessidade de uso de arquivos externos.

Visite o post: https://pctoledo.org/forum/viewtopic.php?t=1362

@braços :?)
Responder