DBF para MySQL com gravação dupla

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
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

DBF para MySQL com gravação dupla

Mensagem por JoséQuintas »

Vou colocar aqui como faço minha conversão de DBF pra MySQL, utilizando essa técnica que fiz com gravação dupla.
Uso minha classe de cadastros, mas tudo bem, seria no mesmo estilo caso ela não existisse.
Usar mais a parte teórica, porque a prática está relacionada com meu uso, então o fonte pode não servir pra outras situações.

Primeiro uma prévia das rotinas padrão, no meu caso dentro da classe:

- primeiro - GO TO TOP
- último - GO TO BOTTOM
- anterior - SKIP -1
- próximo - SKIP
- específico - é um GET no código pra posicionar
- tela de dados - é um SAY geral ou um GET geral

Essa parte acima é padrão, por isso agrupei uma classe.
Ao usar para um cadastro, faço herança, e substituo os métodos específico e tela dados, porque estes dois são diferentes pra cada cadastro.
No caso de vocês, que não tem classe, tudo bem, as rotinas acima seriam rotinas fixas, que são copiadas de um fonte para o outro.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

DBF para MySQL com gravação dupla

Mensagem por JoséQuintas »

Primeiro passo:

Como fazer no mysql o equivalente às rotinas padrão de DBF?

A forma que encontrei foi me basear no código, a partir do código atual (se precisar), localizar no arquivo.

Primeiro:
no DBF tá indexado, é GOTO TOP
Equivale ao primeiro código, de uma lista em ordem crescente.
SELECT CODIGO FROM CLIENTES ORDER BY CODIGO LIMIT 1

Último:
Idem, GOTO BOTTOM
Equivale ao último código, de uma lista em ordem decrescente.
SELECT CODIGO FROM CLIENTES ORDER BY CODIGO DESC LIMIT 1

Seguinte:
Idem, SKIP
Equivale ao menor código maior que o atual.
Pegando os códigos maiores que o atual, em ordem crescente, é o primeiro da lista.
SELECT CODIGO FROM CLIENTES WHERE CODIGO > CodigoAtual ORDER BY CODIGO LIMIT 1

Anterior:
SKIP -1
Equivale ao primeiro código MENOR que o atual.
Pegando os códigos menores que o atual, em ordem decrescente, é o primeiro da lista.
SELECT CODIGO FROM CLIENTES WHERE CODIGO < CodigoAtual ORDER BY CODIGO DESC LIMIT 1

Pronto, parte padrão resolvida.
Já tem rotinas pra substituição, apenas está resolvido, não que já coloque em uso.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

DBF para MySQL com gravação dupla

Mensagem por JoséQuintas »

Alterando o fonte propriamente dito:

As rotinas anteriores, por enquanto são anotações apenas.

A primeira parte na conversão é atualizar DBF e MySQL ao mesmo tempo.
Então... aonde tem o REPLACE no DBF, acrescento o UPDATE para o MySQL.
E aonde tem o APPEND, acrescento o INSERT para o MySQL.

A partir daqui, gravação dupla, DBF e MySQL estão atualizados.
Mesmo esquema do DBF apenas atualiza o MySQL.

A partir daqui, poderia atualizar relatórios e outras pesquisas !!!
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

DBF para MySQL com gravação dupla

Mensagem por JoséQuintas »

Confirmado que DBF e MySQL estão sincronizados, mesma gravação nos dois...
Todo aplicativo pode pesquisar no MySQL ao invés do DBF.
browses, relatórios, etc. todos podem usar MySQL.

O primeiro da lista são os browses, pra ganho de velocidade.
Se a alteração foi suficiente, também relatórios e outras pesquisas.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

DBF para MySQL com gravação dupla

Mensagem por JoséQuintas »

O próximo passo é tornar o MySQL como principal.
Aqui entram aquelas rotinas que foram anotadas.
Num primeiro momento, o SEEK nos DBFs vai posicionar no registro, após pesquisar no MySQL.
Desta forma, o fonte vai ter a informação do DBF ou do MySQL, mas pode aguardar pra ser alterado pra MySQL depois.
Se o fonte pega do DBF funciona, e se pega do MySQL funciona, apenas o MySQL começa a ser o principal, o ponto de partida para prosseguir.

Neste ponto, posso usar o campo incremental do MySQL pra fornecer o próximo código disponível.
E uso esse código pra salvar tanto no MySQL como no DBF.

Neste momento, o aplicativo passa a ter a vantagem do campo incremental único, enquanto continua salvando em DBF e MySQL.
Qualquer pesquisa/relatório podendo ser atualizado pra MySQL, sem depender do DBF.
Dá até pra usar DBF e MySQL ao mesmo tempo, até se acostumar a buscar toda informação somente no SQL.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

DBF para MySQL com gravação dupla

Mensagem por JoséQuintas »

Depois disso, trata-se apenas de não usar mais o DBF.

Se alterar só o arquivo de clientes, não vai ser suficiente pra transformar um relatório de notas fiscais por cliente totalmente pra MySQL, mas talvez possa alterar o relatório de clientes.
Se alterar só o arquivo de notas fiscais, idem, mas talvez possa pelo menos buscar as notas fiscais, e pesquisar os clientes via DBF.
Se alterar os dois, pode fazer totalmente em MySQL.

Justamente por isso mudei minha conversão:
Comecei alterando um arquivo por vez pra MySQL, mas notei que se fossem vários, teria mais vantagem.

Neste ponto dá pra comparar SQLMIX com ADO, ou esse esquema de alteração:

Vantagem do SQLMIX sobre ADO: não alterar o fonte na parte de leitura, mas precisa alterar gravação igual ADO, pra comandos SQL.
Vantagem do SQL: consultas trazendo somente o que interessa, o que só é obtido com alteração de fonte, caso contrário fica pior do que com DBF.
Conclusão: a vantagem do SQLMIX é.... aproveitar fonte que vai ser jogado fora, ganhar tempo de conversão deixando mais lento do que deveria ser.
E o pior: pode dar a falsa impressão de que SQL é demorado, porque o fonte não foi feito pra SQL e sim pra DBF.

Por outro lado, é lógico, depende do programador.
Esse mesmo esquema que usei pra ADO poderia ser usado pra SQLMIX.
Do mesmo jeito que estou alterando relatórios pra tirar proveito do MySQL usando ADO, também poderia ser usado no SQLMIX.

Acho que o maior problema do SQLMIX NÃO é o SQLMIX, mas o fato dele dar a impressão ao programador que vai continuar trabalhando igual DBF.

SQL é relativamente simples, mas o programador precisa entender que SQL é SQL, e DBF é DBF.
E ficar usando SQL igual DBF não é uma boa maneira do programador entender isso.

Não sei se seria exagero dizer o seguinte:
SQLMIX é ótimo, pra quem já está acostumado com SQL, e não pra principiante que está começando a entrar no mundo SQL.
Quem já está acostumado com SQL, sabe muito bem a diferença, mas quem está começando.... vai entender cada vez menos.

o ADO deixa mais claro isso, mas nem sei se mesmo assim o pessoal entendeu.
Basicamente são duas variáveis:
uma variável é a conexão, é o elo de ligação entre o programa e o servidor

oConexao := win_OleCreateObject( "ADODB.Connection" )

Outra variável é a resposta do servidor, contendo qualquer coisa.
É enviar o comando e obtém-se a resposta em uma variável.

oTemporario := oConexao:Execute( "comando sql" )

Podemos fazer consultas diferentes, em variáveis diferentes, mas isso é uma variável contendo a resposta do servidor em formato ADO.
É o Windows que faz isso, talvez seja array, talvez seja arquivo temporário, não faço idéia, apenas é fazer uso disso.

Com certeza o SQLMIX faz algo parecido, mas na maior parte do tempo é um SELECT *, trás tudo, quando nem precisamos de tudo.
Mas é lógico, como eu disse, depende do programador ENTENDER do que se trata SQL, e impedir que isso seja feito.
O fato do SQLMIX trazer em formato DBF, não significa que isso virou DBF.

Até mesmo hbmysql... qual a vantagem de trazer o processamento ao aplicativo, se o Windows faz isso sozinho e mais rápido?

De qualquer forma, só existe ADO no WINDOWS.
Mas nada impede do programador usar ADO pra ENTENDER SQL, e só depois adotar o SQLMIX da forma correta, ou pra usar no Linux, ou pra permitir usar os browses de libs gráficas que só atendem DBF ou Array.

Na prática o ADO é igual uma RDD, com muito mais recursos do que comandos SQL, mas.... podem entrar particularidades do ADO.

Como comparação:

O jeito que eu mostro ADO aqui no fórum, seria o mesmo do que usar SQLMIX apenas com o Execute().
E se o ADO morrer?

- executar comandos
- executar comandos trazendo retorno

Se uma LIB fizer isso, o que todas fazem, ninguém está nem preso ao ADO e nem ao Windows, pode trocar quando quiser.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

DBF para MySQL com gravação dupla

Mensagem por JoséQuintas »

Tinha esquecido de alterar o cadastro pra MySQL.... começando a alterar agora.
Vejam esta rotina:

Código: Selecionar todos

METHOD Email() CLASS JPCADASTROClass

   LOCAL cAssunto, cTxt, mIdCadastro

   mIdCadastro := ::axKeyValue[ 1 ]
   IF mIdCadastro == 0
      MsgWarning( "Selecione primeiro o cliente" )
      RETURN NIL
   ENDIF
   Encontra( StrZero( mIdCadastro, 6 ), "JPCADASTRO", "NUMLAN" )
   IF Empty( jpcadastro->cdEmail )
      MsgWarning( "Cliente não contém endereço de email" )
      RETURN NIL
   ENDIF
   IF ! MsgYesNo( "Confirme o envio de email" )
      RETURN NIL
   ENDIF
   cAssunto = "Cad." + Str( mIdCadastro, 6 ) +  " " + jpcadastro->cdNome

   cTxt := []
   cTxt += [<html font size="2">]
   cTxt += [<table width="95%">]
   cTxt += [<tr><td></td></tr>]
   cTxt += [<tr><td align="CENTER">FICHA DE CADASTRO</td></tr>]
   cTxt += [<tr><td></td></tr>]
   cTxt += [<tr><td>CÓDIGO: ] + jpcadastro->idCadastro + [</td></tr>]
   cTxt += [<tr><td>NOME: ] + jpcadastro->cdNome +  [</td></tr>]
   cTxt += [<tr><td>ENDEREÇO: ] + jpcadastro->cdEndereco + [</td></tr>]
   cTxt += [<tr><td>BAIRRO: ] + jpcadastro->cdBairro + [</td></tr>]
   cTxt += [<tr><td>CIDADE: ] + jpcadastro->cdCidade + [</td></tr>]
   cTxt += [<tr><td>UF: ] + jpcadastro->cdUf +   [</td></tr>]
   cTxt += [<tr><td>CEP: ] + jpcadastro->cdCep + [</td></tr>]
   cTxt += [<tr><td>CPF-CNPJ: ] + jpcadastro->cdCnpj + [</td></tr>]
   cTxt += [<tr><td>INSCR.ESTADUAL: ] + jpcadastro->cdInsEst +   [</td></tr>]
   cTxt += [<tr><td>OUTRO DOCTO: ] + jpcadastro->cdOutDoc +  [</td></tr>]
   cTxt += [<tr><td>EMAIL: ] + jpcadastro->cdEmail +  [</td></tr>]
   cTxt += [<tr><td></td></tr>]
   cTxt += [</table></font></html>]
   EnviaEmail( { Trim( jpcadastro->cdEmail ) },, cAssunto, cTxt )

   RETURN NIL
Ao alterar a rotina principal pra MySQL, o código chave é este:
mIdCadastro := ::axKeyValue[ 1 ]

Esta parte posiciona o DBF:
Encontra( StrZero( mIdCadastro, 6 ), "jpcadastro", "numlan" )

e a rotina segue usando o DBF.
Ou seja... mesmo passando a usar MySQL na rotina principal, ainda funciona buscar informações do DBF pra esta rotina.

Agora basta alterar esta rotina pra usar informações do MySQL e não do DBF.

O mais importante:
Funcionava antes com DBF, instalado no cliente.
Funciona agora alterado parcialmente pra MySQL, se eu instalar AGORA no cliente continua funcionando.
Vai funcionar depois de alterar esta rotina pra MySQL, e se instalar no cliente depois, no cliente continua funcionando.

Entenderam a vantagem da gravação dupla?
Ficamos livres pra alterar qualquer coisa a qualquer momento.

Mas o melhor é: tranquilidade
O que seria um problemão de converter todo aplicativo, foi transformado em probleminhas de solução rápida.
É já fazer e já liberar.

Se está terminado ou não, não importa, o que importa é que está sempre funcionando.
E seja DBF ou MySQL, os dois estão sempre atualizados e disponíveis pra uso.

Lembrando:
NÃO tenho nenhum problema com DBF compartilhado em rede.
Se não tenho problema com DBF, e nem problema com MySQL, a gravação dupla funciona perfeito.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

DBF para MySQL com gravação dupla

Mensagem por JoséQuintas »

Código: Selecionar todos

METHOD Email() CLASS JPCADASTROClass

   LOCAL cAssunto, cEmail, cTxt, mIdCadastro

   mIdCadastro := ::axKeyValue[ 1 ]
   IF mIdCadastro == 0
      MsgWarning( "Selecione primeiro o cliente" )
      RETURN NIL
   ENDIF
   WITH OBJECT ::cnSQL
      :cSQL := "SELECT * FROM JPCADASTRO WHERE IDCADASTRO = " + NumberSQL( mIdCadastro )
      :Execute()
      cEmail := :String( "CDEMAIL" )
      cAssunto = "Cad." + Str( mIdCadastro, 6 ) +  " " + :String( "CDNOME" )
      cTxt := []
      cTxt += [<html font size="2">]
      cTxt += [<table width="95%">]
      cTxt += [<tr><td></td></tr>]
      cTxt += [<tr><td align="CENTER">FICHA DE CADASTRO</td></tr>]
      cTxt += [<tr><td></td></tr>]
      cTxt += [<tr><td>CÓDIGO: ] + Str( mIdCadastro, 6 ) + [</td></tr>]
      cTxt += [<tr><td>NOME: ] + :String( "CDNOME" ) +  [</td></tr>]
      cTxt += [<tr><td>ENDEREÇO: ] + :String( "CDENDERECO" ) + [</td></tr>]
      cTxt += [<tr><td>BAIRRO: ] + :String( "CDBAIRRO" ) + [</td></tr>]
      cTxt += [<tr><td>CIDADE: ] + :String( "CDCIDADE" ) + [</td></tr>]
      cTxt += [<tr><td>UF: ] + :String( "CDUF" ) + [</td></tr>]
      cTxt += [<tr><td>CEP: ] + :String( "CDCEP" ) + [</td></tr>]
      cTxt += [<tr><td>CPF-CNPJ: ] + :String( "CDCNPJ" ) + [</td></tr>]
      cTxt += [<tr><td>INSCR.ESTADUAL: ] + :String( "CDINSEST" ) +   [</td></tr>]
      cTxt += [<tr><td>OUTRO DOCTO: ] + :String( "CDOUTDOC" ) +  [</td></tr>]
      cTxt += [<tr><td>EMAIL: ] + :String( "CDEMAIL" ) +  [</td></tr>]
      cTxt += [<tr><td></td></tr>]
      cTxt += [</table></font></html>]
      :CloseRecordset()
   ENDWITH
   IF Empty( cEmail )
      MsgWarning( "Cliente não contém endereço de email" )
      RETURN NIL
   ENDIF
   IF ! MsgYesNo( "Confirme o envio de email" )
      RETURN NIL
   ENDIF

   EnviaEmail( { cEmail },, cAssunto, cTxt )

   RETURN NIL
Pronto agora só MySQL.
Alterei a montagem pra antes da checagem e confirmação.
Porque isso?
Se um comando SQL já trás tudo, nem faço comandos intermediários, já pego o que interessa e encerro o uso do "temporário".
Só pra ter menos fonte.
O tempo de processamento aí nem importa, 1 segundo a mais ou a menos, não faz diferença.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

DBF para MySQL com gravação dupla

Mensagem por JoséQuintas »

A que ponto chega a gravação dupla:

Código: Selecionar todos

METHOD TelaDados( lEdit ) CLASS JPCADASTROClass

   LOCAL GetList := {}, cBloqueioDesc
   LOCAL cnSQL := ADOClass():New( AppConexao() )
   LOCAL mIdCadastro, mcdEndereco, mcdNumero, mcdCompl, mcdBairro, mcdCidade, mcdUf, mcdCep
   LOCAL mcdContato, mcdTelefone, mcdFax, mcdEndCob, mcdNumCob, mcdComCob, mcdBaiCob, mcdCidCob
   LOCAL mcdUFCob, mcdCepCob, mcdConCob, mcdTelCob, mcdFaxCob, mcdNomEnt, mcdEndEnt, mcdNumEnt
   LOCAL mcdComEnt, mcdBaiEnt, mcdCidEnt, mcdUFEnt, mcdCepEnt, mcdConEnt, mcdTelEnt, mcdFaxEnt
   LOCAL mcdNome, mcdApelido, mcdLimCre, mcdEmail, mcdEmaNfe, mcdEmaCon, mcdValMes, mcdCnpj
   LOCAL mcdInsEst, mcdOutDoc, mIdTriCad, mIdVendedor, midPortador, mIdForPag, mIdCliSta
   LOCAL mcdMapa, mIdMidia, mcdDivisao, mcdGrupo, mcdHomePage, mcdCnae, mIdTransp, mcdObs
   LOCAL mcdTelef2, mcdTelef3, mcdDatNas, mcdInfInc, mcdInfAlt, mcdCtaCon, mcdCtaJur, mcdCtaDes

   mIdCadastro := ::axKeyValue[ 1 ]
   WITH OBJECT cnSQL
      :cSQL := "SELECT * FROM JPCADASTRO"
      :Execute()
      Encontra( StrZero( mIdCadastro, 6 ), "jpcadastro", "numlan" )
      mcdEndereco := jpcadastro->cdEndereco
      mcdNumero   := jpcadastro->cdNumero
      mcdCompl    := jpcadastro->cdCompl
      mcdBairro   := jpcadastro->cdBairro
      mcdCidade   := jpcadastro->cdCidade
      mcdUf       := jpcadastro->cdUf
      mcdCep      := jpcadastro->cdCep
      mcdContato  := jpcadastro->cdContato
      mcdTelefone := jpcadastro->cdTelefone
      mcdFax      := jpcadastro->cdFax
      mcdEndCob   := jpcadastro->cdEndCob
      mcdNumCob   := jpcadastro->cdNumCob
      mcdComCob   := jpcadastro->cdComCob
      mcdBaiCob   := jpcadastro->cdBaiCob
      mcdCidCob   := jpcadastro->cdCidCob
      mcdUFCob    := jpcadastro->cdUFCob
      mcdCepCob   := jpcadastro->cdCepCob
      mcdConCob   := jpcadastro->cdConCob
      mcdTelCob   := jpcadastro->cdTelCob
      mcdFaxCob   := jpcadastro->cdFaxCob
      mcdNomEnt   := jpcadastro->cdNomEnt
      mcdEndEnt   := jpcadastro->cdEndEnt
      mcdNumEnt   := jpcadastro->cdNumEnt
      mcdComEnt   := jpcadastro->cdComEnt
      mcdBaiEnt   := jpcadastro->cdBaiEnt
      mcdCidEnt   := jpcadastro->cdCidEnt
      mcdUFEnt    := jpcadastro->cdUFEnt
      mcdCepEnt   := jpcadastro->cdCepEnt
      mcdConEnt   := jpcadastro->cdConEnt
      mcdTelEnt   := jpcadastro->cdTelEnt
      mcdFaxEnt   := jpcadastro->cdFaxEnt
      mcdNome     := jpcadastro->cdNome
      mcdApelido  := jpcadastro->cdApelido
      mcdLimCre   := jpcadastro->cdLimCre
      mcdEmail    := jpcadastro->cdEmail
      mcdEmaNfe   := jpcadastro->cdEmaNfe
      mcdEmaCon   := jpcadastro->cdEmaCon
      mcdValMes   := jpcadastro->cdValMes
      mcdCnpj     := jpcadastro->cdCnpj
      mcdInsEst   := jpcadastro->cdInsEst
      mcdOutDoc   := jpcadastro->cdOutDoc
      mIdTriCad   := Val( jpcadastro->cdTriCad )
      mIdVendedor := Val( jpcadastro->cdVendedor )
      midPortador := Val( jpcadastro->cdPortador )
      mIdForPag   := Val( jpcadastro->cdForPag )
      mIdCliSta   := Val( jpcadastro->cdStatus )
      mcdMapa     := jpcadastro->cdMapa
      mIdMidia    := Val( jpcadastro->cdMidia )
      mcdDivisao  := jpcadastro->cdDivisao
      mcdGrupo    := jpcadastro->cdGrupo
      mcdHomePage := jpcadastro->cdHomePage
      mcdCnae     := jpcadastro->cdCnae
      mIdTransp   := Val( jpcadastro->cdTransp )
      mcdObs      := jpcadastro->cdObs
      mcdTelef2   := jpcadastro->cdTelef2
      mcdTelef3   := jpcadastro->cdTelef3
      mcdDatNas   := jpcadastro->cdDatNas
      mcdInfInc   := jpcadastro->cdInfInc
      mcdInfAlt   := jpcadastro->cdInfAlt
      mcdCtaCon   := jpcadastro->cdCtaCon
      mcdCtaJur   := jpcadastro->cdCtaJur
      mcdCtaDes   := jpcadastro->cdCtaDes
      :CloseRecordset()
   ENDWITH
Já alterei pra pesquisar do MySQL, mas ainda mantendo a pesquisa no DBF.
Posso até alterar parcial de onde vém os campos.
Vai que entra ligação telefônica durante a alteração, posso liberar até pegando um campo de cada lugar.

Como dá pra perceber aí, existem campos que no DBF ainda são caractere.
Já fixei no aplicativo pra ser numérico, então na leitura/gravação do DBF converto de acordo com o tipo, mas já está resolvido pra MySQL.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

DBF para MySQL com gravação dupla

Mensagem por JoséQuintas »

Código: Selecionar todos

METHOD TelaDados( lEdit ) CLASS JPCADASTROClass

   LOCAL GetList := {}, cBloqueioDesc
   LOCAL cnSQL := ADOClass():New( AppConexao() )
   LOCAL mIdCadastro, mcdEndereco, mcdNumero, mcdCompl, mcdBairro, mcdCidade, mcdUf, mcdCep
   LOCAL mcdContato, mcdTelefone, mcdFax, mcdEndCob, mcdNumCob, mcdComCob, mcdBaiCob, mcdCidCob
   LOCAL mcdUFCob, mcdCepCob, mcdConCob, mcdTelCob, mcdFaxCob, mcdNomEnt, mcdEndEnt, mcdNumEnt
   LOCAL mcdComEnt, mcdBaiEnt, mcdCidEnt, mcdUFEnt, mcdCepEnt, mcdConEnt, mcdTelEnt, mcdFaxEnt
   LOCAL mcdNome, mcdApelido, mcdLimCre, mcdEmail, mcdEmaNfe, mcdEmaCon, mcdValMes, mcdCnpj
   LOCAL mcdInsEst, mcdOutDoc, mIdTriCad, mIdVendedor, midPortador, mIdForPag, mIdCliSta
   LOCAL mcdMapa, mIdMidia, mcdDivisao, mcdGrupo, mcdHomePage, mcdCnae, mIdTransp, mcdObs
   LOCAL mcdTelef2, mcdTelef3, mcdDatNas, mcdInfInc, mcdInfAlt, mcdCtaCon, mcdCtaJur, mcdCtaDes

   mIdCadastro := ::axKeyValue[ 1 ]
   WITH OBJECT cnSQL
      :cSQL := "SELECT * FROM JPCADASTRO"
      :Execute()
      Encontra( StrZero( mIdCadastro, 6 ), "jpcadastro", "numlan" )
      mcdEndereco := jpcadastro->cdEndereco
      mcdNumero   := jpcadastro->cdNumero
      mcdCompl    := jpcadastro->cdCompl
      mcdBairro   := jpcadastro->cdBairro
      mcdCidade   := jpcadastro->cdCidade
      mcdUf       := jpcadastro->cdUf
      mcdCep      := jpcadastro->cdCep
      mcdContato  := jpcadastro->cdContato
      mcdTelefone := jpcadastro->cdTelefone
      mcdFax      := jpcadastro->cdFax
      mcdEndCob   := jpcadastro->cdEndCob
      mcdNumCob   := jpcadastro->cdNumCob
      mcdComCob   := jpcadastro->cdComCob
      mcdBaiCob   := jpcadastro->cdBaiCob
      mcdCidCob   := jpcadastro->cdCidCob
      mcdUFCob    := jpcadastro->cdUFCob
      mcdCepCob   := jpcadastro->cdCepCob
      mcdConCob   := jpcadastro->cdConCob
      mcdTelCob   := jpcadastro->cdTelCob
      mcdFaxCob   := jpcadastro->cdFaxCob
      mcdNomEnt   := jpcadastro->cdNomEnt
      mcdEndEnt   := jpcadastro->cdEndEnt
      mcdNumEnt   := jpcadastro->cdNumEnt
      mcdComEnt   := jpcadastro->cdComEnt
      mcdBaiEnt   := jpcadastro->cdBaiEnt
      mcdCidEnt   := jpcadastro->cdCidEnt
      mcdUFEnt    := jpcadastro->cdUFEnt
      mcdCepEnt   := jpcadastro->cdCepEnt
      mcdConEnt   := jpcadastro->cdConEnt
      mcdTelEnt   := jpcadastro->cdTelEnt
      mcdFaxEnt   := jpcadastro->cdFaxEnt
      mcdNome     := jpcadastro->cdNome
      mcdApelido  := jpcadastro->cdApelido
      mcdLimCre   := :Number( "CDLIMCRE" )
      mcdEmail    := jpcadastro->cdEmail
      mcdEmaNfe   := jpcadastro->cdEmaNfe
      mcdEmaCon   := jpcadastro->cdEmaCon
      mcdValMes   := :Number( "CDVALMES" )
      mcdCnpj     := jpcadastro->cdCnpj
      mcdInsEst   := jpcadastro->cdInsEst
      mcdOutDoc   := jpcadastro->cdOutDoc
      mIdTriCad   := :Number( "CDTRICAD" )
      mIdVendedor := :Number( "CDVENDEDOR" )
      midPortador := :Number( "CDPORTADOR" )
      mIdForPag   := :Number( "CDFORPAG" )
      mIdCliSta   := :Number( "CDSTATUS" )
      mcdMapa     := jpcadastro->cdMapa
      mIdMidia    := :Number( "CDMIDIA" )
      mcdDivisao  := jpcadastro->cdDivisao
      mcdGrupo    := jpcadastro->cdGrupo
      mcdHomePage := jpcadastro->cdHomePage
      mcdCnae     := jpcadastro->cdCnae
      mIdTransp   := :Number( "CDTRANSP" )
      mcdObs      := jpcadastro->cdObs
      mcdTelef2   := jpcadastro->cdTelef2
      mcdTelef3   := jpcadastro->cdTelef3
      mcdDatNas   := jpcadastro->cdDatNas
      mcdInfInc   := jpcadastro->cdInfInc
      mcdInfAlt   := jpcadastro->cdInfAlt
      mcdCtaCon   := jpcadastro->cdCtaCon
      mcdCtaJur   := jpcadastro->cdCtaJur
      mcdCtaDes   := jpcadastro->cdCtaDes
      :CloseRecordset()
   ENDWITH
Por enquanto alterei os numéricos pra virem do MySQL, os demais vou ter que confirmar o tamanho da string.
Um detalhe interessante da minha classe aí é o seguinte: esses serão numéricos, NÃO IMPORTA se no MySQL são numéricos ou caractere.
Caso eu não tenha alterado ainda no MySQL, posso alterar depois, sem ter que mexer no fonte !!!
Ficou uma mão na roda isso.
Pra strings, eu até poderia alterar a classe pra pegar o tamanho direto da estrutura, mas achei que ficou mais flexível assim, porque facilita em browse, relatórios, etc.
E se fosse ambiente GUI, não precisaria disso, porque geralmente é definido no layout de tela/impressão.

Talvez até seja por isso que preferem uma IDE e/ou um gerador de relatórios.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

DBF para MySQL com gravação dupla

Mensagem por JoséQuintas »

Pra estrutura, não tem muito o que fazer, ou o HeidiSQL, ou o fonte que cria a tabela em DBF ou MySQL.
stru.png
Dá pra ver mais embaixo que mantive o posicionamento do DBF.
É que não sei ainda se algum VALID pode usar o registro atual.
Fica assim por precaução, até terminar.

Ah é..... quanto de desempenho vou perder por fazer um SEEK no DBF? praticamente nulo.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
Itamar M. Lins Jr.
Administrador
Administrador
Mensagens: 7928
Registrado em: 30 Mai 2007 11:31
Localização: Ilheus Bahia
Curtiu: 1 vez

DBF para MySQL com gravação dupla

Mensagem por Itamar M. Lins Jr. »

Ola!
Vc está declarando as variáveis fora do padrão.

Código: Selecionar todos

lVar := .F./.T. //Logical
nVar := 0 //Numeric
dVar := Date() //Date
cVar := 'ABC' //Character
mVar := observação // Campo Memo
xVar := 0,1,2 ou 'ABC' //Numeric, Character
mData, mIdade, mEndereco... Não se usa mais, não é recomendado.

Saudações,
Itamar M. Lins Jr.
Saudações,
Itamar M. Lins Jr.
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

DBF para MySQL com gravação dupla

Mensagem por JoséQuintas »

É que uso padronizado pra destacar o que vém de arquivo.
Se no arquivo é IdCadastro, em memória é mIdCadastro.

Mas pensando bem...
já estou começando a me perder sobre o que mudei ou não pra numérico.
o prefixo pode até ajudar agora.
Antes era sempre caractere, e agora não.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
claudiochaves
Usuário Nível 1
Usuário Nível 1
Mensagens: 35
Registrado em: 28 Jul 2017 15:48
Localização: campinas/sp

DBF para MySQL com gravação dupla

Mensagem por claudiochaves »

JoséQuintas escreveu:Alterando o fonte propriamente dito:

As rotinas anteriores, por enquanto são anotações apenas.

A primeira parte na conversão é atualizar DBF e MySQL ao mesmo tempo.
Então... aonde tem o REPLACE no DBF, acrescento o UPDATE para o MySQL.
E aonde tem o APPEND, acrescento o INSERT para o MySQL.

A partir daqui, gravação dupla, DBF e MySQL estão atualizados.
Mesmo esquema do DBF apenas atualiza o MySQL.

A partir daqui, poderia atualizar relatórios e outras pesquisas !!!
Ola, estou estudando sua técnica para agilizar minha migração, primeiro obrigado pela contribuição. No caso do update no mysql, você faz a clausula com todos os campos ou apenas os campos que tiveram alteração ? isto não ficou claro para mim.

Obrigado, abraços,
Claudio Chaves
Desenvolvedor
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

DBF para MySQL com gravação dupla

Mensagem por JoséQuintas »

claudiochaves escreveu:No caso do update no mysql, você faz a clausula com todos os campos ou apenas os campos que tiveram alteração ? isto não ficou claro para mim.
É uma gravação equivalente ao DBF.
Se no DBF gravava tudo, no MySQL também gravo tudo, e se era parcial, continua parcial.

O que era

REPLACE A1 WITH V1, A2 WITH V2, A3 WITH V3

foi substituído por um array bidimensional

{ { a1, v1 }, { a2, v2 }, { a3, v3 } }

Só pra dar idéia do uso disso no DBF:

SELECT TABELA
FOR EACH oCampo IN CamposList
REPLACE &( oCampo[ 1 ] ) WITH oCampo[ 2 ]
NEXT

Só pra dar idéia do uso no MySQL:

"INSERT INTO TABELA ( " + lista de campos do array + " ) VALUES ( " + lista de valores do array + ")"

O mesmo na alteração, sendo que:

No DBF: primeiro um SEEK pra posicionar antes do replace

No MySQL: indicar a chave UPDATE TABELA SET CAMPO1=VALOR1,... WHERE chave = x
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Responder