Clipper On Line • Ver Tópico - ADO, outra vez, de outra forma

ADO, outra vez, de outra forma

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

Moderador: Moderadores

 

ADO, outra vez, de outra forma

Mensagempor JoséQuintas » 16 Jul 2020 20:49

O ideal é usar uma classe mesmo, pra evitar encher de código nos fontes.

Basicamente é criar uma conexão com o banco de dados, configurar, e abrir.

oConexao := win_OleCreateObject( "ADODB.Connection" )
oConexao:ConnectionString := ""
... outras configurações
oConexao:Open()


E no final do programa fechar:

oConexao:Close()


Lógico... tem caso de conexão cair, principalmente se for internet, então uma classe pode usar a controlar tudo isso, ao invés de colocar em cada fonte.

O resto, de um modo geral, é comando SQL.
É o aplicativo enviando mensagem pro servidor, e o servidor respondendo.

Inclusão? é usando o comando SQL de incluir, passa lá o comando com os nomes dos campos e os valores

oConexao:Execute( "INSERT INTO CLIENTES ( NOME, ENDERECO ) VALUES ( 'nome do cara', 'endereco do cara' )" )


Exclusão? é usado o comando SQL pra excluir. passa lá o comando e o que quer excluir

oConexao:Execute( "DELETE FROM CLIENTES WHERE CODIGO = 10" )


Alteração? é usado o comando SQL pra atualizar e passa lá o que quer alterar

oConexao:Execute( "UPDATE CLIENTES SET NOME='novo nome' WHERE CODIGO = 10" )


E buscar informações, este talvez seja o ponto diferente entre usar ADO, SQLMIX, hbMySQL, etc.

oResultado := oConexao:Execute( "SELECT * FROM CLIENTES" )


Qual a diferença entre ADO, SQLMIX, hbMySQL neste ponto?
o ADO retorna no formato ADO, uma classe da Microsoft
o SQLMIX retorna no formato parecido com DBF - parece DBF mas não tem nada no disco (eu acho)
o hbMySQL retorna no formato Array

CADA um retorna em seu próprio formato, em cada um vai usar de um jeito diferente.
Isso não é visível para o programador, não é um arquivo físico, é apenas o modo de usar.

O formato do ADO é o chamado recordset.
Por isso, na maioria dos fontes, seja Visual Basic ou não, costumam usar Rs como variável
TANTO FAZ o nome, é uma variável.

oResultado := oConexao:Execute( "SELECT ..." )
Rs := oConexao:Execute( "SELECT ..." )
oConsulta := oConexao:Execute(  "SELECT ..." )
oTemporario := oConexao:Execute( "SELECT ..." )
clientes := oConexao:Execute( "SELECT * FROM CLIENTES" )


O ponto chave nisso, é que não fica preso a usar um único arquivo, como no DBF.
Dá pra usar tudo, de tudo que é lugar, junto, misturado, tratado, filtrado, relacionado, somado, organizado....
A única coisa que o aplicativo precisa é essa conexão, pra trocar mensagens com o servidor.

Isso, por si só, já é uma grande diferença entre usar DBF.
Por isso não existe nada mágico que faça tudo automático.
Se fizer automático... vai estar usando SQL igual DBF, o que pode ficar um lixo.

O ponto que sempre chamei atenção sobre o ADO é que ele deixa bem claro qual é a diferença entre DBF e SQL.

Voltando ao recordset do ADO.
Ele tem a maioria das coisas que usamos no DBF, mas não com o mesmo nome:

ADO:Eof()
ADO:Bof()
ADO:RecordCount()
ADO:MoveFirst()
ADO:MoveNext()
ADO:MovePrevious()
ADO:Fields:Count()

E o campo pode ser acessado por número ou letra, sendo que o menor é ZERO e não 1.
ADO:Fields( "CODIGO" ):Value
ADO:Fields( 0 ):Value
ado:Fields( 10 ):Value

Juntando tudo isso, uma rotina pra listar ficaria assim:

oConsulta := oConexao:Execute( "SELECT * FROM CLIENTES ORDER BY NOME" )
DO WHILE ! oConsulta:Eof()
   ? oConsulta:Fields( "CODIGO" ):Value
   ? oConsulta:Fields( "NOME" ):Value
   ? oConsulta:Fields( "ENDERECO" ):Value
   oConsulta:MoveNext()
ENDDO
oConsulta:Close()


É relativamente simples, é isso, e o resto, tudo tem a ver com comandos SQL, recursos do servidor SQL.

Lógico, até se acostumar, vai longe.
Exemplos:

- SQL não aceita data zerada/vazia " / / "
- SQL ACEITA NULO, digamos o NIL do Harbour
- SQL geralmente trata data como sendo campo datetime
- Se no SQL o campo é string com 30 posições, dá erro se tentar gravar com 40
- SQL aceita campo string VARIÁVEL, pode ter de 0 a infinitos caracteres
E por aí vai

Pode deixar compatível com DBF?
Até pode.... mas não compensa.
Fixar um texto com 80 posições, pra facilitar no programa, por exemplo.
De repente 1 milhão de registros com texto vazio ocupa nada, mas se fixar 80 posições, vai ocupar 80 milhões de caracteres.

E é justamente aí que entra o que falei, de usar uma classe.
Já pensou em todos os fontes, ficar tratando nulo, tamanho de string, etc. etc. etc. ?
Pois é.

E outra: e se você for fazer um programa pra uma base SQL que já existe?
Então... acaba sendo interessante trabalhar com o SQL no padrão dele, sem ficar configurando coisas diferentes.
Vai ficar preparado pra qualquer coisa que possa acontecer.

REFORÇANDO:

ADO é apenas um intermediário, que usa o formato ADO.
HBMYSQL é outro intermediário, que usa o formato Array
SQLMIX é outro intermediário, que usa o formato DBF.
O SQLMIX se divide, porque mesmo usando igual DBF, internamente ele pode se conectar com ODBC, por exemplo, que abre possibilidade pra outros bancos de dados, igual o ADO.

Qual deles é melhor?
O melhor é o servidor, e usar o servidor ao máximo, usando comandos SQL.
TODAS as opções permitem isso.

Por um lado, o ADO já te deixa visível exatamente do que se trata, isso pode ser bom pra aprender, mas talvez não pra usar.
Por outro lado, o SQLMIX te dá a oportunidade de usar mais rápido, facilitando boa parte da complicação que seria usar diretamente.
hbMySQL seria por array, vai de cada um ter dificuldade ou não com array

Qual deles é melhor?
Tem tanta coisa pra aprender sobre SQL, se ficar querendo decidir o que usar, só vai perder tempo.
Usa o que se sentir mais confortável e pronto.
O importante é começar a fazer testes, entender o funcionamento da troca de mensagens, entender a diferença entre DBF e servidor SQL.

O resto vém com o tempo.

NÃO é sair convertendo todo aplicativo.
É primeiro fazer testes, e ir se acostumando, ir se sentindo confortável.
Coloca alguma coisa simples pra teste, que o aplicativo possa funcionar com ou sem isso, e vai se aprofundando aos poucos, e tendo certeza que tudo está funcionando.
Só depois vai mais fundo.
O tempo vai dizer a hora certa... mas... lógico... você precisa dar um empurrãozinho pra esse tempo não virar uma eternidade.
José M. C. Quintas
Harbour 3.4, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, hbnetio, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
Avatar de usuário

JoséQuintas
Colaborador

Colaborador
 
Mensagens: 14689
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 13 vezes
Mens.Curtidas: 864 vezes

ADO, outra vez, de outra forma

Mensagempor JoséQuintas » 16 Jul 2020 21:01

Só mais uma, pra ficar reforçado e bem claro:

O SQL se resume nisso:

troca de mensagens com o servidor

Quer incluir? manda a mensagem com o que deseja incluir

Quer consultar? manda a mensagem pedindo as informações, e as informações vém como resposta.

É isso.

Compare com mensagens do whatsapp
Você pede pra alguém te enviar uma foto, e esse alguém envia.
Você envia a mensagem: cadastre aí na sua agenda este telefone que dá pra pedir pizza... a pessoa cadastra
Você envia a mensagem: me mande uns telefones de pizzaria que você conhece.... e a pessoa te envia
Mensagem: me mande os totais de vendas, por cliente, totalizados por produto, em ordem alfabética.... ao contrário do SQL, a resposta pode ser: faça você mesmo kkkkk

Pois é... parece complicado, de tão simples que é...
José M. C. Quintas
Harbour 3.4, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, hbnetio, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
Avatar de usuário

JoséQuintas
Colaborador

Colaborador
 
Mensagens: 14689
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 13 vezes
Mens.Curtidas: 864 vezes

ADO, outra vez, de outra forma

Mensagempor Fernando queiroz » 16 Jul 2020 23:06

eu estou fazendo exatamente como você falou, me adaptei muito bem ao SQL , facilitou muito as coisas

so queria fazer uma classe para executar os comando e controlar as quedas de conecção
HARBOUR 3.2, HWGUI 2.22 B4, SEFAZCLASS, DBFCDX, PDFClass, LETODBF
Fernando queiroz
Usuário Nível 3

Usuário Nível 3
 
Mensagens: 440
Data de registro: 12 Nov 2014 23:41
Cidade/Estado: Porto Alegre/RS
Curtiu: 6 vezes
Mens.Curtidas: 16 vezes

ADO, outra vez, de outra forma

Mensagempor Vlademiro » 16 Jul 2020 23:47

Enquanto lia o que vcs escreveram me ocorreu uma ideia: porque não cria uma função que sempre retorna a mesma conexão ADO ?

// Na abertura de todas as conexões faça assim
oCon := ADOSingleton()

Não fecha ela...

Dentro da função usa uma variável static para receber a classe de conexão e dá um jeito de verificar se essa conexão está ativa, tipo enviando um select qualquer só para testar.
Se não estiver ativa inicia ela de novo. Usa os blocos de erro BEGIN SEQUENCE WITH __breakblock() ...

Eu vou postar uma adaptação de uma classe singleton
FUNCTION ADOSingleton()

    LOCAL oError
    STATIC oConn // Tem que ser static

    IF Empty( oConn )  // Se não tiver sido inicializada, inicializa
        oConn := ADOConnection objeto
    ENDIF

    // Poderia testar a conexão aqui
    BEGIN SEQUENCE WITH __breakblock()
         oConn:Execute("Select version()") // Um select qualquer simples só para testar
   RECOVER USING oError
         Instancia de novo oConn
    ENDSEQUENCE

    RETURN oConn // Retorna o objeto



Nos seus relatórios, pesquisas, etc , em vez de instanciar o oConn de novo, basta chamar assim

LOCAL oConn := ADOSingleton()

Não testei, fiz uma adaptação de um código que uso aqui para outros fins, mas a lógica é a mesma
Avatar de usuário

Vlademiro
Usuário Nível 4

Usuário Nível 4
 
Mensagens: 674
Data de registro: 11 Jul 2005 02:46
Curtiu: 14 vezes
Mens.Curtidas: 50 vezes

ADO, outra vez, de outra forma

Mensagempor JoséQuintas » 17 Jul 2020 01:42

Já pensei nisso mas.... uso mais de um servidor SQL, e não adiantaria fazer sigleton.

Mas uso assim:

STATIC pConexao 

FUNCTION AppConexao()
   RETURN pConexao


Mesmo em multithread, a conexão padrão continua única.

Nos módulos:

LOCAL cnSQL := ADOClass():New( AppConexao() )

Além de na classe geral ter lá:

VAR cnSQL INIT ADOClass():New( AppConexao() )

E no módulo da classe, na maioria das vezes usar ::cnSQL

Quando preciso diferente, declaro diferente, por exemplo

LOCAL cnSQL := ADOClass():New( ConexaoInternet() )
LOCAL cnSQL := ADOClass():New( ConexaoExcel() )

E por aí vai.
José M. C. Quintas
Harbour 3.4, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, hbnetio, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
Avatar de usuário

JoséQuintas
Colaborador

Colaborador
 
Mensagens: 14689
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 13 vezes
Mens.Curtidas: 864 vezes

ADO, outra vez, de outra forma

Mensagempor Vlademiro » 17 Jul 2020 01:47

Basta criar duas funções. Uma para cada conexão. Ou criar um hash dentro da função que retorne a conexão selecionada. Essa sua função vai tratar algum erro ? Parece que só serve para retornar uma string...
Avatar de usuário

Vlademiro
Usuário Nível 4

Usuário Nível 4
 
Mensagens: 674
Data de registro: 11 Jul 2005 02:46
Curtiu: 14 vezes
Mens.Curtidas: 50 vezes

ADO, outra vez, de outra forma

Mensagempor Vlademiro » 17 Jul 2020 01:49

Se retornar o objeto então resolve o problema, mas não fiz teste pra confirmar. Ainda estou usando pouco o ADO.
Avatar de usuário

Vlademiro
Usuário Nível 4

Usuário Nível 4
 
Mensagens: 674
Data de registro: 11 Jul 2005 02:46
Curtiu: 14 vezes
Mens.Curtidas: 50 vezes

ADO, outra vez, de outra forma

Mensagempor JoséQuintas » 17 Jul 2020 01:52

No meu caso, a classe mistura conexão e recordset.

WITH OBJECT cnSQL
   :cSQL := "SELECT * ..."
   :Execute()
   DO WHILE ! :Eof()
      ? :String( "NOME" )
       :MoveNext()
   ENDDO
   :CloseRecordset()
ENDWITH


De um modo geral, a classe repassa para conexão ou recordset ou o que precisar
Apenas exemplo

CLASS ADOClass
   VAR cnSQL
   VAR RS
   VAR cSQL INIT ""
   METHOD New( cnSQL ) INLINE ::cnSQL := cnSQL
   METHOD Eof()  INLINE ::Rs:Eof()
   METHOD MoveNext() INLINE ::Rs:MoveNext()
   METHOD CloseRecordset() INLINE ::Rs:Close()
   METHOD Field(...) INLINE ::Rs:Field(...)
   METHOD Close() INLINE ::cnSQL:Close()
   METHOD RecordCount() INLINE ::Rs:RecordCount()
   METHOD Filter( cValue )  INLINE ::rs:Filter := cValue
   METHOD Execute() INLINE ::rs := ::cnSQL:Execute( ::cSQL )
ENDCLASS
José M. C. Quintas
Harbour 3.4, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, hbnetio, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
Avatar de usuário

JoséQuintas
Colaborador

Colaborador
 
Mensagens: 14689
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 13 vezes
Mens.Curtidas: 864 vezes

ADO, outra vez, de outra forma

Mensagempor JoséQuintas » 17 Jul 2020 01:55

Ah sim, com a classe dá pra evitar erros, por exemplo:

METHOD Eof() INLINE iif( ::Rs == NIL, .T., ::Rs:Eof() )


Se recordset estiver vazio, Eof() dá erro, então desse jeito evita o erro, dá pra testar eof() à vontade.
José M. C. Quintas
Harbour 3.4, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, hbnetio, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
Avatar de usuário

JoséQuintas
Colaborador

Colaborador
 
Mensagens: 14689
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 13 vezes
Mens.Curtidas: 864 vezes




Retornar para Contribuições, Dicas e Tutoriais

Quem está online

Usuários vendo este fórum: Nenhum usuário registrado online e 3 visitantes


Ola Amigo, espero que meu site e forum tem lhe beneficiado, com exemplos e dicas de programacao.
Entao divulgue o link da Doacao abaixo para seus amigos e redes sociais ou faça uma doacao para o site forum...
MUITO OBRIGADO PELA SUA DOACAO!
Faça uma doação para o forum
cron
v
Olá visitante, seja bem-vindo ao Fórum Clipper On Line!
Efetue o seu login ou faça o seu Registro