Meu uso de ADO
Enviado: 21 Set 2021 21:21
É só um comentário sobre meus fontes, que devo postar de vez em quando.
Meu uso de ADO parece ADO... mas não é
É que uso uma classe intermediária.
Até poderia alterar o ADO original da Microsoft, pelo Harbour, mas preferi assim.
O ADO tem Eof(), MoveNext(), Fields(), Move(), etc. e minha classe também, apenas não é diretamente a função do ADO.
Isso teoricamente retorna um recordset ADO, mas na prática não é totalmente verdade.
Se não tem nada, não retorna nada, NIL, nada mesmo, não um recordset com zero registros.
Se não tem conteúdo, como é que vai criar uma estrutura pra um retorno sem nenhum campo?
É... porque se SELECT é pra pesquisar campos diversos, como pode existir uma estrutura pré-definida pra não se sabe o que?
Pois é...
Por isso eu criei a classe temporária.
Testar EOF() em nada... não dá.
Seria algo como NIL:Eof()
Imagine em tudo que é fonte, ficar testando se o retorno é NIL, se o campo existe pra não dar erro, se tem conteúdo antes de testar EOF(), etc. etc. etc.
Complicado... então criei a classe intermediária que evita todos esses erros, e toda necessidade dessa checagem, porque ela já faz.
A classe, de certa forma, é relativamente simples: tem o recordset, e tem funções que são repassadas ao recordset.
Acima apenas exemplo inicial.
EOF() da classe vai testar EOF() no recordset.
Como eu disse antes, se testar eof() em vazio dá erro.
Com a classe intermediária, basta eu fazer isso na classe.
Pronto, acabei com a necessidade de gambiarras em fontes pra teste adicional, basta eu usar essa classe intermediária.
Outro problema: MoveNext(), que seria o SKIP do DBF, dá erro se já estiver em EOF() e tentar pular para o próximo registro.
E também dá erro se fizer no arquivo vazio (NIL).
Vai precisar de 2 testes adicionais, os mesmos do EOF() e mais um pra testar EOF().
Mas dá pra aproveitar o que já existe, de eof()
Pronto, problemas resolvidos.
Não vai dar erro se for Nil, também não vai dar erro se já estiver em Eof().
E por aí vai.
Foi pra isso que criei a classe intermediária, pra não precisar ficar tratando erros em tudo que é fonte.
Poderia alterar o nome de MoveNext() pra Skip(), pra ficar igual DBF, mas preferi deixar com o nome original.
Também embuti a conexão como parte da classe, mais o método Execute(), e também teste pra verificar se deu erro no execute, pegando mensagem de erro do ADO.
Por isso, quando ver fontes que eu posto, pode dar a impressão de que essa parte é tratada automaticamente pelo ADO, mas não é.
Fica meio parecido com ADO, mas não é exatamente/diretamente o ADO.
Em ADO seria mais como isto:
Como eu disse, parece... mas não é.
Nesse fonte faltaria o teste de Nil, por exemplo, que minha classe intermediária acaba tornando desnecessário.
NÃO SEI o que acontece na SQLMIX num caso desses, porque provavelmente deve acontecer também, do MySQL não retornar NADA.
Apenas comentário, NÃO estou falando nada contra, apenas é um comentário de que realmente não sei como isso é tratado.
No caso do ADO dá erro, é a classe que criei que evita dar erro, ou testes que sejam colocados nos fontes.
E voltando à minha classe....
Aproveitei pra adicionar recursos, que já postei por aqui, como o :ReturnSelect( "SELECT 1" )
Isso evita muito fonte adicional.
E é por aí que a gente vai simplificando nossa vida... (ou às vezes complicando) kkkk
Meu uso de ADO parece ADO... mas não é
É que uso uma classe intermediária.
Até poderia alterar o ADO original da Microsoft, pelo Harbour, mas preferi assim.
O ADO tem Eof(), MoveNext(), Fields(), Move(), etc. e minha classe também, apenas não é diretamente a função do ADO.
Código: Selecionar todos
oTemporario := oConexao:Execute( "SELECT NOME FROM CLIENTES WHERE CODIGO=1" )
Se não tem nada, não retorna nada, NIL, nada mesmo, não um recordset com zero registros.
Se não tem conteúdo, como é que vai criar uma estrutura pra um retorno sem nenhum campo?
É... porque se SELECT é pra pesquisar campos diversos, como pode existir uma estrutura pré-definida pra não se sabe o que?
Pois é...
Por isso eu criei a classe temporária.
Testar EOF() em nada... não dá.
Seria algo como NIL:Eof()
Imagine em tudo que é fonte, ficar testando se o retorno é NIL, se o campo existe pra não dar erro, se tem conteúdo antes de testar EOF(), etc. etc. etc.
Complicado... então criei a classe intermediária que evita todos esses erros, e toda necessidade dessa checagem, porque ela já faz.
A classe, de certa forma, é relativamente simples: tem o recordset, e tem funções que são repassadas ao recordset.
Código: Selecionar todos
CLASS ADOClass
VAR oRecordset
METHOD Eof() INLINE ::oRecordset:Eof()
METHOD MoveNext() INLINE ::oRecordset:MoveNext()
ENDCLASS
EOF() da classe vai testar EOF() no recordset.
Como eu disse antes, se testar eof() em vazio dá erro.
Com a classe intermediária, basta eu fazer isso na classe.
Código: Selecionar todos
METHOD Eof() INLINE iif( ::oRecordset == Nil, .T., ::oRecordset:Eof() )
Outro problema: MoveNext(), que seria o SKIP do DBF, dá erro se já estiver em EOF() e tentar pular para o próximo registro.
E também dá erro se fizer no arquivo vazio (NIL).
Vai precisar de 2 testes adicionais, os mesmos do EOF() e mais um pra testar EOF().
Mas dá pra aproveitar o que já existe, de eof()
Código: Selecionar todos
METHOD MoveNext() INLINE iif( ::oRecordset:Eof(), Nil, ::oRecordset:MoveNext() )
Não vai dar erro se for Nil, também não vai dar erro se já estiver em Eof().
E por aí vai.
Foi pra isso que criei a classe intermediária, pra não precisar ficar tratando erros em tudo que é fonte.
Poderia alterar o nome de MoveNext() pra Skip(), pra ficar igual DBF, mas preferi deixar com o nome original.
Também embuti a conexão como parte da classe, mais o método Execute(), e também teste pra verificar se deu erro no execute, pegando mensagem de erro do ADO.
Por isso, quando ver fontes que eu posto, pode dar a impressão de que essa parte é tratada automaticamente pelo ADO, mas não é.
Código: Selecionar todos
cnSQL := ADOLocal() // deixei de usar ADOClass():New( AppConexao() )
WITH OBJECT cnSQL
:Execute( "SELECT CODIGO FROM CLIENTES" )
DO WHILE ! :Eof()
? :Number( "CODIGO" ), :String( "NOME" )
:MoveNext()
ENDDO
:CloseRecordset()
ENDWITH
Em ADO seria mais como isto:
Código: Selecionar todos
cnSQL := win_OleCreate( "ADODB.Connection" )
cnSQL:.....
cnSQL:Open()
oRs := cnSQL:Execute( "SELECT ..." )
WITH OBJECT oRs
DO WHILE ! oRs:Eof()
? :Fields( "CODIGO" ):Value, :Fields( "NOME" ):Value
:MoveNext()
ENDDO
:Close()
ENDWITH
cnSQL:Close()
Nesse fonte faltaria o teste de Nil, por exemplo, que minha classe intermediária acaba tornando desnecessário.
NÃO SEI o que acontece na SQLMIX num caso desses, porque provavelmente deve acontecer também, do MySQL não retornar NADA.
Apenas comentário, NÃO estou falando nada contra, apenas é um comentário de que realmente não sei como isso é tratado.
No caso do ADO dá erro, é a classe que criei que evita dar erro, ou testes que sejam colocados nos fontes.
E voltando à minha classe....
Aproveitei pra adicionar recursos, que já postei por aqui, como o :ReturnSelect( "SELECT 1" )
Isso evita muito fonte adicional.
E é por aí que a gente vai simplificando nossa vida... (ou às vezes complicando) kkkk