Retornar a Conexão do banco de Dados

Projeto [x]Harbour - Compilador de código aberto compatível com o Clipper.

Moderador: Moderadores

Avatar do usuário
Antonio
Usuário Nível 3
Usuário Nível 3
Mensagens: 347
Registrado em: 14 Ago 2003 17:33
Localização: Sao Paulo - SP
Contato:

Retornar a Conexão do banco de Dados

Mensagem por Antonio »

Boa tarde pessoal.
Estou tentando implementar um classe de conexão com um BD.

Código: Selecionar todos

#include "adodb.ch"
#include "hbclass.ch"

CLASS TConexao
	DATA dbRs       INIT "ADODB.Connection" 
	DATA dbDriver   INIT "{PostgreSQL UNICODE}"
	DATA dbDataBase INIT "Plainning"
	DATA dbServer   INIT "127.0.0.1" 
	DATA dbPort     INIT 5432
	DATA dbUser     INIT "postgres"
	DATA dbPassword INIT "ccccccc"
	
	METHOD conectar() CONSTRUCTOR
	METHOD desconectar()
ENDCLASS
/*
METHOD novo() CLASS TConexao
	::dbUser     := NIL
	::dbPassword := NIL
RETURN Self
*/
METHOD conectar( cUser, cPass ) CLASS TConexao
       public dbConn
       Try
	 dbConn:= win_oleCreateObject( "ADODB.Connection"  )
	 dbConn:Open("Driver={PostgreSQL UNICODE};Server=127.0.0.1;Port=5432;Database=plainning;Uid=postgres;Pwd=ccccccc;" )   
		 MsgBox ( "CONETADO", "Plainning",,)
		
	   Catch err
	      MsgBox( "Deu Ruim")
		  dbConn:Close()
	   end 
RETURN Self

METHOD desconectar() CLASS TConexao
	dbRecSet:Close()
RETURN dbConn


Estou fazendo a chamada assim:

Código: Selecionar todos

#include <hmg.ch>

declare window Main

Function main_button_teste_action
	
	oConn:= TConexao():conectar("postgres", "mypassword")
	dbCommand :="select * FROM tab_ctspagar;"
	dbRecSet := oConn:EXECUTE ( dbCommand )

	
	do while .not. dbRecSet:eof()
     msgbox( str( dbRecSet:fields["cpo_numero"]:VALUE ) +" "+  sTr( dbRecSet:fields["cpo_data"]:VALUE ) +" "+ str( dbRecSet:fields["cpo_valor"]:VALUE ), "splain" )
     dbRecSet:MoveNext()
	enddo
	
Return Nil
A conexão com o BD é feita normalmente mas ocorre o problema que esta na imagem:
O que eu queria é instanciar a classe fazendo com que o oBjeto da conexão ficasse disponivel/visivel a todo o sistema para assim, executar os métodos.
Agradeço a ajuda.
Obrigado
Anexos
classe conexao II.png
Antonio Carlos
Harbour 3.2 (20180213)
Hwgui 2.20 3b | PostGresql 9.5 | ADO/ODBC
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Retornar a Conexão do banco de Dados

Mensagem por JoséQuintas »

Uso assim em multithread:

Código: Selecionar todos

STATIC AppcnMySqlLocal := NIL

FUNCTION AppcnMySqlLocal()

   IF AppcnMySqlLocal == NIL
       AppcnMySqlLocal := MySqlConnection( "xxx", , "xxx" )
   ENDIF

   RETURN AppcnMySqlLocal
E nas rotinas:

Código: Selecionar todos

LOCAL cnMySql := ADOClass():New( AppcnMySqlLocal() )

cnMySql:cSql := "SELECT * FROM CLIENTES"
cnMySql:Execute()
DO WHILE .NOT. cnMySql:Eof()
   ? cnMySql:Value( "CODIGO" )
   cnMySql:MoveNext()
ENDDO
cnMySql:Rs:Close()
Minha classe já tem recordset e tudo mais junto.
Por isso acabo criando instâncias da classe, e não da conexã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/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Retornar a Conexão do banco de Dados

Mensagem por JoséQuintas »

Só pra curiosidade, sem tratamento de erros algo mais ou menos assim:

Código: Selecionar todos

CREATE CLASS ADOClass

   VAR Connection
   VAR Rs
   VAR cSql

   METHOD New( oCn )         INLINE ::Connection := oCn
   METHOD Value( cCampo )    INLINE ::Rs:Fields( cCampo ):Value
   METHOD Eof()              INLINE ::Rs:Eof()
   METHOD MoveFirst()        INLINE ::Rs:MoveFirst()
   METHOD MoveLast()         INLINE ::Rs:MoveLast()
   METHOD RecordCount()      INLINE ::Rs:RecordCount()
   METHOD Execute( cSql )    INLINE ::Rs := ::Connection:Execute( iif( cSql == NIL, ::cSql, cSql ) )
   METHOD ExecuteCmd( cSql ) INLINE ::Connection:Execute( iif( cSql == NIL, ::cSql, cSql ) )

   ENDCLASS
Por falar nisso... como não fecho a conexão na classe, mais fácil criar um close do recordset nela, pra evitar esquecimento e fechar a conexão por engano.

Código: Selecionar todos

METHOD Close() INLINE ::Rs:Close()
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
Vlademiro
Usuário Nível 4
Usuário Nível 4
Mensagens: 752
Registrado em: 11 Jul 2005 02:46

Retornar a Conexão do banco de Dados

Mensagem por Vlademiro »

Você não criou o método EXECUTE. É isso que a mensagem está dizendo.

Faz tempo que não uso ADODB, mas eu tentaria mais ou menos assim :

1 ) Não criaria uma variável public dbConn, eu faria assim :

Código: Selecionar todos

     DATA dbConn // Nas definições da classe
2 ) Apagaria a linha public dbConn e alteraria a referencia dbConn por ::dbConn no método conectar, já que ele agora é interno a classe

3 ) Criaria o meu método execute

Código: Selecionar todos


METHOD Execute( cSuaQuery ) CLASS TConexao

    
RETURN  ::dbConn.Execute( cSuaQuery ) 

Agora sim, o Execute é visível.


Você pode evoluir a sua classe mais adiante, criando outros métodos. A vantagem é que ela pode abranger a vários banco de dados. Evite usar variáveis públicas dentro de objetos.
Avatar do usuário
asimoes
Colaborador
Colaborador
Mensagens: 4919
Registrado em: 26 Abr 2007 16:48
Localização: RIO DE JANEIRO-RJ

Retornar a Conexão do banco de Dados

Mensagem por asimoes »

Vlademiro

É isso
::dbConn.Execute( cSuaQuery )

Ou isso: ?

::dbConn:Execute( cSuaQuery )
►Harbour 3.x | Minigui xx-x | HwGui◄
Pense nas possibilidades abstraia as dificuldades.
Não corrigir nossas falhas é o mesmo que cometer novos erros.
A imaginação é mais importante que o conhecimento. (Albert Einstein)
Avatar do usuário
Vlademiro
Usuário Nível 4
Usuário Nível 4
Mensagens: 752
Registrado em: 11 Jul 2005 02:46

Retornar a Conexão do banco de Dados

Mensagem por Vlademiro »

Com dois pontos asimoes

::dbConn:Execute( cSuaQuery )

Valeu.

Aproveito para acrescentar que a solução do Quintas é a mais completa, e sugiro ao Antonio não ir logo usando ela pois seria melhor para ele aprender esses pequenos detalhes e ir ele mesmo desenvolvendo a sua classe. Ele pode ir desenvolvendo, postando suas duvidas aqui e ir olhando as classes já desenvolvidas, como a do Quintas. Seria mais proveitoso assim...
Avatar do usuário
Antonio
Usuário Nível 3
Usuário Nível 3
Mensagens: 347
Registrado em: 14 Ago 2003 17:33
Localização: Sao Paulo - SP
Contato:

Retornar a Conexão do banco de Dados

Mensagem por Antonio »

Muito obrigado a todos!
Jose Quintas é bem sofisticada a sua metodologia.

Eu estou usando um arquivo de cabeçalho que encontrei em um exemplo da minigui. adodb.ch
Parece que voces não fazem o uso deste.

Não me encontrei ainda.

Grato
Antonio Carlos
Harbour 3.2 (20180213)
Hwgui 2.20 3b | PostGresql 9.5 | ADO/ODBC
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Retornar a Conexão do banco de Dados

Mensagem por JoséQuintas »

Só voltando um pouco atrás:

A conexão é... uma conexão. Uma classe de conexão parece não trazer nenhum recurso adicional pra conexão.
Basta uma variável.

O que meu aplicativo faz: cria no início, fecha no final (exceto as de uso temporário)

Minha função da conexão está assim, pode até criar uma pra cada tipo de banco de dados:

Código: Selecionar todos

FUNCTION MySqlConnection( cServer, nPort, cDatabase, cUser, cPassword, nVersion )

   LOCAL cnConnection

   hb_Default( @cServer, "nomeservidor" )
   hb_Default( @cDatabase, "nomebancodedados" )
   hb_Default( @nPort, 3306 )
   hb_Default( @cUser, "usuario" )
   hb_Default( @cPassword, "senha" )
   hb_Default( @nVersion, 3 )

   cnConnection:= win_OleCreateObject( "ADODB.Connection" )
   cnConnection:ConnectionString := "Driver={MySQL ODBC " + iif( nVersion == 3, "3.51", "5.3 ANSI" ) + " Driver};Server=" + cServer + ";" + "Port=" + Ltrim( Str( nPort ) ) + ;
      ";Stmt=;Database=" + cDatabase + ";User ID=" + cUser + ";Password=" + cPassword + ";Collation=latin1;" + ;
      "AUTO_RECONNECT=1;COMPRESSED_PROTO=0;PAD_SPACE=1" // usando compactação impede certas checagens // Option=131072;
   cnConnection:CursorLocation    := AD_USE_CLIENT
   cnConnection:CommandTimeOut    := 200 // seconds
   cnConnection:ConnectionTimeOut := 200 // seconds
   // cnConnection:ConnectionString := "Driver={MySQL ODBC 5.3 ANSI Driver};Server=" + cServer + ";" + "Port=" + Ltrim( Str( nPort ) ) + ;

   RETURN cnConnection
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

Retornar a Conexão do banco de Dados

Mensagem por JoséQuintas »

E a classe contém o recordset embutido, vou colocando coisas conforme vou achando que pode facilitar.
Tratamento de campo nulo, geração pra dbf, no execute testar se conexão está aberta, etc.

Código: Selecionar todos

CREATE CLASS ADOClass

   VAR    Cn
   VAR    Rs
   VAR    cSql
   VAR    oStructure

   METHOD New( oConnection )           INLINE ::CN := oConnection, SELF
   METHOD Open( lError )
   METHOD Close()
   METHOD Execute( cSql, lError )    // Atualiza Rs com retorno
   METHOD ExecuteCmd( cSql, lError ) // Despreza retorno
   METHOD ExecuteDbf( cSql )
   METHOD StringSql( xField, nLen )
   METHOD NumberSql( xField )
   METHOD DateSql( xField )
   METHOD Value( xField )
   METHOD ValueSQL( xField )           INLINE ::Value( xField )
   METHOD Replace( cFrom, cTo )
   METHOD Eof()                        INLINE iif( ::Rs:RecordCount() == 0, .T., ::Rs:Eof() )
   METHOD MoveFirst()                  INLINE ::Rs:MoveFirst()
   METHOD MoveNext()                   INLINE ::Rs:MoveNext()
   METHOD SQLToDBF( lStruAuto ) // usar ExecuteDbf()
   METHOD Count( cSql )
   METHOD TableList()
   METHOD TableExists( cTable )
   METHOD FieldList( cTable )
   METHOD FieldExists( cField, cTable )
   METHOD AddField( cField, cTable, cSql )
   METHOD DeleteField( cField, cTable, cDbf )
   METHOD IndexList( cTable )
   METHOD RecordCount()                INLINE ::Rs:RecordCount()

   END CLASS
Nota:

o INLINE é só uma economia de fonte. Quando a função é muito pequena, usando INLINE coloca direto na declaração, sem função separada para o método.

Exemplo:

Código: Selecionar todos

FUNCTION Teste() ; RETURN "ok"

METHOD Teste() INLINE "ok"
ou comparando:

Código: Selecionar todos

CREATE CLASS ...
   METHOD Teste()
   END CLASS

METHOD Teste() CLASS ...
   RETURN "ok"
//---------------------------
CREATE CLASS ...
   METHOD Teste() INLINE "ok"
   END CLASS
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

Retornar a Conexão do banco de Dados

Mensagem por JoséQuintas »

Acréscimo:

Algumas aí foram temporárias e não eliminei.
Porque eu errava o nome, então coloquei dois nomes, como Value() e ValueSQL()
Ou porque decidi alterar o nome no meio do caminho, e deixei os dois nomes até terminar de alterar todos os fontes
Ou porque dependendo do ODBC, o tipo não é convertido corretamente, então StringSql() garante que vai ser convertido pra string.
Como tenho ODBC 3.51 e 5.3 nos clientes, e cada um se comporta diferente, algumas coisas vão ficar aí até terminar de trocar todos.

SqlToDBf e ExecuteToDbf também, são a mesma coisa, mas talvez altere o nome novamente.... rs
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
Vlademiro
Usuário Nível 4
Usuário Nível 4
Mensagens: 752
Registrado em: 11 Jul 2005 02:46

Retornar a Conexão do banco de Dados

Mensagem por Vlademiro »

Quintas, nas minhas classes eu até comecei fazendo assim (conexão e recordset na mesma classe), mas me deparei com um problema : nos CRUDs que eu criava eu primeiro abria um Grid para depois chamar o Formulário. Alguns métodos do Grid (Recordset) não tem relação com o Formulário. Por exemplo: nos forms eu tenho o método Insert, Update e Delete. No Grid eu tenho o método NextPage, PreviousPage, etc.

Ficou assim :

Código: Selecionar todos

TVladSQL  +---->  TVladSQLBrowser
          |
          +----> TVladSQLFrm     

Documentação da TVladSQL : http://sistema.lia.ufc.br/robodoc/TVlad ... ml#robo116
Documentação da TVladSQLBrowser : http://sistema.lia.ufc.br/robodoc/TVlad ... tml#robo77
Documentação da TVladSQLFrm : http://sistema.lia.ufc.br/robodoc/TVlad ... tml#robo61
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Retornar a Conexão do banco de Dados

Mensagem por JoséQuintas »

Você trabalha diferente do jeito que eu trabalho.
Considero o recordset igual a um arquivo temporário.
Não me preocupo em manter posição, ou seja lá o que for.
No caso do browse uso um recordset só pra ele, e até converto pra DBF.
Ao alterar num browse, por exemplo, a partir do ID atualizo o MySQL.
Achei mais prático assim, do que enfrentar particularidades.

É isso que indica lá na minha conexão o CursorLocation AD_USE_CLIENT
É praticamente como se o aplicativo estivesse desconectado da base, mesmo mantendo conexão aberta.
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
Vlademiro
Usuário Nível 4
Usuário Nível 4
Mensagens: 752
Registrado em: 11 Jul 2005 02:46

Retornar a Conexão do banco de Dados

Mensagem por Vlademiro »

Entendi, os arquivos temporários que vc trabalha são DBFs, e na hora de pegar os dados do servidor fica mais pratico fazer com uma classe com tudo junto (Conexão e Recordset). Quando os dados chegam você os trata localmente usando os DBFs. Quando você vai gravar os dados você os converte de volta para o banco de dados.
Avatar do usuário
Vlademiro
Usuário Nível 4
Usuário Nível 4
Mensagens: 752
Registrado em: 11 Jul 2005 02:46

Retornar a Conexão do banco de Dados

Mensagem por Vlademiro »

Vou postar um teste de sistema que fiz usando HMG. Lá tem as classes que fiz até agora, os formulários e o banco em postgreSQL.

Vou postar na seção Minigui do fórum. Lá da pra ver como eu fiz o CRUD gravando no postgreSQL.
Responder