Pular para o conteúdo principal

Lazarus - Acessando banco de dados com SQLdb - Parte II

Form de Cliente

No DataModule já deve ter uma TSQLQuery e um TDataSource devidamente configurados para acesso à tabela Cliente. Vamos então inserir um novo form no programa definindo Name como frmCliente, Caption como Clientes. Mande salvar e informe u_cliente no nome da unit. Acesse o editor de código referente a esse form e abaixo de Implementation, para permitir que a unit u_cliente tenha acesso aos objetos do DataModule, digite:

uses u_dmdados;

Volte ao form e inclua um TPanel da mesma forma que foi feito para o form de Cidade. Selecione um TDBNavigator da aba Data Controls e coloque sobre o painel. Defina a propriedade DataSource como dsCliente. Insira um TSpeedButton da aba Additional no painel e o configure semelhante ao que fizemos no form de Cidade, inclusive definindo o código do evento OnClick para fechar o form. O form de Cliente deverá ter essa aparência:


Coloque dois TDBedit no form, o primeiro deve ter Name definido como edIdCliente, DataSource como dsCliente e DataField como ID_CLIENTE. No segundo defina Name como edNome, DataSource como dsCliente e DataField como NOME. Coloque dois TLabel para identificar esse campos e defina os Caption de acordo com a figura anterior.
O componente TDBLookupComboBox é usado para que, no caso de uma chave estrangeira (ID_CIDADE na tabela Cliente), o usuário possa escolher o registro na tabela referenciada (Cidade). Neste componente os dados da tabela referenciada são mostrados em uma lista. Pegue então um componente desses na aba Data Controls e coloque no form abaixo do segundo TDBEdit. Defina Name como dblIdCidade, DataSource como dsCliente e DataField como ID_CIDADE. Para definir a lista primeiramente defina a propriedade ListSource como dsCidade, na propriedade ListField (campo que será visualizado na lista) defina NOME e KeyField (campo chave) defina como ID_CIDADE. Existe ainda a propriedade Sorted que define se a lista estará ordenada e Style que define o comportamento do controle. Deixe Sorted como True e Style como dsDropDownList (o usuário não poderá digitar no controle, apenas selecionar da lista). Coloque um TLabel para identificar este campo.
Coloque mais um TDBEdit abaixo do LookupComboBox. Defina Name como edTelefone, DataSource como dsCliente e DataField como TELEFONE. Coloque um TLabel para fazer a identificação do campo.
O campo TIPO da tabela Cliente é usado para informar se o cliente é pessoa física - representado pela letra F - ou pessoa jurídica - representado pela letra J. Para este controle vamos usar um TDBRadioGroup, que permite que sejam definidas opções para serem selecionadas. Pegue um componente desses e o coloque no form. Defina a propriedade Caption como Tipo e Name como rgTipo. DataSource será dsCliente e DataField será TIPO. Clique no botão da propriedade Items. Será aberta uma janela com o editor de strings. Digite Pessoa física na primeira linha e Pessoa jurídica na segunda e pressione OK. Na propriedade Columns digite 2 para que as opções apareçam em linha. Clique no botão da propriedade Values - onde estão os valores correspondentes às opções definidas em Items. Digite F na primeria linha e J na segunda. Desta forma quando for selecionada a opção Pessoa física será gravado F no banco de dados, e J caso contrário. Redimensione o componente adequadamente.
Finalmente coloque um TDBCheckBox no form. Defina Caption como Ativo e Name como chxStatus. DataSource é definido como dsCliente e em DataField digite STATUS. As propriedades ValueChecked e ValueUnchecked são usadas para definir o que será gravado no campo quando o componente estiver marcado ou não marcado. Como nosso campo no banco de dados é boolean, não é necessário alterar nada.
Para programar a abertura e o fechamento da Query faça de forma análoga ao que foi feito no form de Cidade. Escreva os códigos correspondentes nos eventos OnShow e OnClose de frmCliente.
Mude para o DataModule e selecione queCliente. Selecione a aba Eventos do Inspetor de objetos e dê um duplo clique ao lado do evento AfterPost. Digite o código como na figura:



Note que esse código é ligeiramente diferente do que fizemos para queCidade. Em vez de usarmos CommitRetaining, agora usamos Commit. Commit fecha todas as tabelas abertas, por isso a Query é aberta na linha 68. Na linha 63 guardamos as chave primária do registro atual na variável chave. E depois que a Query é aberta, usamos Locate para localizar o registro correspondente à variável chave. Esta é outra forma de fazer o COMMIT na transação.
Localize o evento AfterDelete da Query. Clique no botão da caixa à direita para selecionar um método existente. Selecione queClienteAfterPost para que a transação seja encerrada da mesma forma quando um registro for excluído.
Agora vamos ao form principal. Na linha uses abaixo de Implementation acrescente u_cliente para que ela fique assim:

uses u_cidade, u_cliente;

Clique no menu Cadastros -> Clientes e no código do evento OnClick digite:

frmCliente.Show;

Execute o programa e chame o form de Cliente para fazer os testes.


Consultas

O próximo passo do desenvolvimento será criar as telas de consulta às tabelas Cidade e Cliente. Neste artigo mostraremos a criação da consulta de cidades. Supomos que a consulta de clientes é análoga e não haverá dificuldade em criá-la.
Para iniciar vamos ao DataModule inserir dois componentes necessários: um TSQLQuery e um TDataSource. Na Query mude Name para queConsCidade. Na propriedade Database selecione dbCliente. Certifique-se que a propriedade Transaction está corretamente definida como trGeral. No TDataSource mude Name para dsConsCidade e DataSet para queConsCidade.
Uma interface de consulta é necessária, portanto deve-se inserir um novo form. Defina Name como frmConsCidade e Caption como Consulta de cidades. Salve e digite u_conscidade no nome da unit.
A consulta irá oferecer duas opções de consulta - pela chave primária ou por parte do nome. Então insira um TRadioGroup da aba Standard. Defina Caption como Campo. Na propriedade Items inclua as linhas Código e Nome. Na propriedade Name digite rgCampo. Redimensione o componente adequadamente.


Observe a figura acima para orientar o seu desenho. Inclua um TEdit da aba Standard. Defina Name como edDado e delete o conteúdo da propriedade Text.
Coloque um TLabel para identificar o campo. Defina Caption como Dado a consultar.
Insira um TButton. Defina Name btnConsultar. Localize o componente TDBGrid na aba Data Controls. Insira um no form. Defina sua propriedade Name com dbgDados. Abra o editor de código e digite abaixo de Implementation:

uses u_dmdados;

Volte ao form e na propriedade DataSource da TDBGrid selecione dsConsCidade. Dê um duplo clique no botão btnConsultar e digite o código:

 

Analisando o código:
linha 39 - define que propriedades e métodos sem referência a um objeto são considerados como sendo de queConsCidade.
linha 41 - fecha a Query.
linha 42 - limpa o conteúdo da propriedade SQL.
linha 43 - verifica que campo foi selecionado no RadioGroup.
linhas 45 e 46 - definem um comando SELECT para buscar linhas na tabela pela chave primária. pIdCidade é um parâmetro definido na linha 46.
linhas 50 e 51 - definem um comando SELECT para buscar linhas na tabela por parte do nome da cidade.
linha 53 - abre a Query.

Mude para o form principal. No editor de código inclua a unit u_conscidade na linha uses abaixo de Implementation. Clique na opção Consultas -> Cidades. Digite o código:

frmConsCidade.Show;

Execute o programa e faça testes de consulta. Falta validar edDado para que aceite apenas dígitos numéricos quando a consulta for direcionada para o campo chave. Deixamos essa tarefa e a criação da consulta de clientes como um exercício.

Baixe aqui o código completo do programa.

Algumas considerações

Durante a criação dessa pequena aplicação encontramos dificuldade em achar relatos de experiências usando os componentes SQLdb. Já utilizamos outros componentes tanto em Lazarus quando no Delphi e sentimos algumas dificuldades principalmente no que diz respeito ao controle de transações. SQLdb só permite um objeto SQLTransaction na aplicação. Isso torna-se um obstáculo quando é necessário abrir mais de um form simultaneamente, pois quando fechamos uma transação todas as tabelas são fechadas. Outra dificuldade refere-se ao ponteiro TBookmark. Antes de encerrar uma transação guardamos o ponteiro do registro atual. Após encerrar a transação, quando o método GotoBookmark() é chamado para posicionar o registro no ponteiro salvo anteriormente ocorre uma exceção. Vale observar que chamar o GotoBookmark() antes de encerrar a transação funciona normalmente. Por esses motivos nos próximos artigos usaremos os componentes ZeosLib.

Comentários

Anônimo disse…
Boa noite Professor Carlos.
Antes de mais nada eu gostaria de agradecer-te em nome de todos os beneficioados por seus tutoriais.

Bem, estou desenvolvendo esta aplicação, porem utilizando o banco de dados MySQL. Está tudo funcionando perfeitamente, porem quando encerro a aplicação, fechando o frmPrincipal, acontece um erro relacionado ao Banco de dados. "trGeral: Operation cannot be performed on an active transaction", estou acompanhando seu tutorial com muita atenção. Onde posso estar errando?
Obrigado.
Professor Carlos disse…
Tente mudar a propriedade Active do SQLTransaction para False. Se não funcionar me escreva
Anônimo disse…
Boa tarde, Professor Carlos.
Encontrei este artigo e resolví construir. Mas logo me deparei com duas dúvidas:
Baixei SQLite3 versão 3.7.10 de 16/01/2012.
O senhor indica digitar "sqlite3 banco.db"
(No meu caso, nada aconteceu)

Mais adiante o senhor explica:
"coloque um TSQLite3Connection no DataModule. Na propriedade
DatabaseName informe o nome do arquivo do banco de dados com o
caminho." Qual seria então este caminho?
Agradeço se puder me ajudar.
Fred.
Professor Carlos disse…
Oi Fred

Conforme eu falei na parte I, o sqlite3 é uma ferramenta de linha de comando para criar o banco e as tabelas. Não vem junto com a dll, mas você pode baixar no próprio site. Mas existem ferramentas visuais mais amigáveis, inclusive um plugin para firefox.
Quanto ao caminho, você deve informar o diretório e o nome do banco de dados, p.ex. /aplicacao/banco/banco.db
Anônimo disse…
Obrigado, Professor.
Sim, eu baixei a ferramenta e a sqlite3.dll (esta, coloquei no system32 do windows).
Minha dúvida principal, é pelo fato de nada acontecer quando digito "sqlite3 banco.db" na ferramenta.
Simplesmente, entra o cursor "...>" e mais nada.
Pode estar havendo algo que eu esteja imterpretando erradamente.
Grato,
Fred.
Professor Carlos disse…
Quando aparecer o prompt digite os comandos de criação de tabelas: create table...
quando vc sair desse programinha usando o comando .quit vc verá que foi criado um arquivo com o nome dado por você qdo chamou o mesmo. Se vc chamar o programa d novo com o mesmo nome de arquivo de banco ele não será criado mais, pois já existe.
Nesse site você pode baixar uma ferramenta visual para fazer isso, se achar melhor http://sqlitebrowser.sourceforge.net/
Anônimo disse…
Bom dia, Professor Carlos!
Baixei o sqlitebrowser, criei o banco, tudo ok.
Após criar os 3 forms, tentei compilar e deu o erro "Illegal unit name: u_cidade", com o nome da unit selecionado no editor.
.
MAS vou tratar de revisar tudo e ver se houve algum erro de minha parte.
Obrigado,
Fred.
Professor Carlos disse…
Se quiser enviar o código fonte pra eu dar uma olhada fique à vontade. Não me ocorre nada sobre o erro sem olhar mais detalhadamente
Anônimo disse…
Boa noite Professor!
Obrigado por todas as dicas postas aqui. Eu fiz esse projeto e tudo correu perfeitamente. Aí me animei a mexer com ele e alterar alguma coisa. Fiquei preso num ponto.
Como posso fazer pra contar os resultados de uma busca? Seja do total de registros ou numa busca específica.
Eu sei do "RowsAffected", mas acho que só funciona quando há modificação na tabela, é certo?
Já agradeço a resposta.
Daniel
Professor Carlos disse…
Tente o RecordCount
Anônimo disse…
Perfeito, Professor!
Ficou fácil agora.
E o programinha foi crescendo! rs
Só falta agora saber a solução para ordenar os resultados onde tenham palavras com acento na primeira letra.
.
No DBGrid, "Árvore de Natal" fica depois de "Banco de Jardim", por exemplo. O resto, tudo ordenado perfeitamente.
Como resolver isso?
Obrigado mais uma vez.
Daniel.
Anônimo disse…
Professor Carlos, boa noite.
Enfim, conseguí encontrar meu erro e o projeto está completo e funcionando.
Agradeço muito, porque aprendí bastante com isso tudo.
Vou continuar buscando seus artigos e suas dicas para aprender mais ainda.
Um bom domingo e obrigado pela atenção.
Fred.
Professor Carlos disse…
Na propriedade CharSet do Connection coloque UTF8
Anônimo disse…
Bom dia Professor!
Infelizmente não adiantou o UTF8 no Charset.
E o problema é SÓ quando tem acento na primeira letra (tipo "Árvore").
O resto fica na ordem perfeita, e as com acento na primeira vão ficando lá pro final.
Testei também com ANSI e não adiantou.

Outra coisa é o RecordCount que só quer contar até 10. rs
Dentro dos 10 primeiros ele funciona.
Quando entro o décimo primeiro registro ele pára no 10 e não conta mais.

Obrigado,
Daniel
Professor Carlos disse…
Qual a versão do Lazarus e do FPC?
JNeto disse…
Professor Carlos, saudações!

Estou precisando da sua ajuda...
Estou fazendo um programa baseado nesse artigo seu, porém estou usando o banco de dados Firebird. Minha dúvida é o seguinte: As linhas do comando de SQL do 'btnConsultar' são diferentes no Firebird (já que vc usou o SQ3Lite...)? Faça a consulta, mas não me traz resultado algum. O DBGrid vem vazio. Estou empolgado a poder mecher novamente com programação, mas encalhei aqui. Pode me ajudar?

Desde já... muito obrigado por compartilhar seus conhecimentos
Professor Carlos disse…
Olá

Os comandos são iguais sim. Veja esse post aqui especifico para Firebird http://professorcarlos.blogspot.com.br/2010/03/lazarus-conectando-firebird.html
Unknown disse…
no meu caso depois de compilado, quando eu chamo o formulario u_cidade da erro near"sintaxe error" o que pode ser
Professor Carlos disse…
Não tem informação suficiente para dizer qual é a causa. Se mandar o código posso tentar ajudar
Anônimo disse…
Tem um bug acontecendo.

Se acessar o formulário cliente, ele não mostra a cidade.

Para ele listar a cidade primeiro tem que visualizar o form cidade e só depois o form de cliente passa exibir os nomes das cidades.

Fiz um teste com seu código e também da o mesmo erro.
Professor Carlos disse…
Olá amigo

Estou muito atarefado em um programa de mestrado. Mas, pediria que você me mandasse o código do seu exemplo pra que eu possa avaliar.

Postagens mais visitadas deste blog

Lazarus - Acessando banco de dados com SQLdb - Parte I

Para fazer nossa primeira aplicação usando banco de dados no Lazarus vamos usar o SQLite e o conjunto de componentes nativo SQLdb. Inicialmente vamos apresentar passo como essa aplicação foi criada. Essa foi a maneira que eu fiz, e eu agradeço sugestões e questionamentos que pessoas que já passaram por essa experiência. Depois irei fazer algumas considerações sobre o uso do SQLdb. SQLite SQLite é uma biblioteca que implementa um motor de banco de dados SQL. É livre para qualquer finalidade, seja uso particular ou comercial. Lê e escreve em um único arquivo que pode ter além de tabelas, índices, gatilhos e visões. Executa em várias plataformas e é indicado para aplicações embarcadas. Maiores detalhes podem ser encontrados no site oficial. Para usá-lo, baixe-o do site e faça a instalação adequada para o seu sistema operacional. No Windows isso é muito simples, apenas copie sqlite3.dll para o system32 da pasta do sistema operacional. Existe uma ferramenta de linha de comando chamada

Tipos de dados no SQLite

Em SQLite, diferente de outros motores de banco de dados, o tipo de dado de um valor está associado com o valor propriamente dito, e não com o seu contêiner. É um sistema de tipo dinâmico. Um campo de uma tabela em SQLite pode receber qualquer tipo de dado. Assim, o SQLite simplesmente ignora o tipo informado no comando CREATE TABLE. Então, dizemos que no SQLite existem classes de armazenamento. E essas classes são: NULL - como em qualquer outro banco de dados. INTEGER - inteiro com sinal, armazenado em 1, 2, 3, 4, 6 ou 8 bytes dependendo da grandeza do valor. REAL - valor de ponto flutuante armazenado em 8 bytes. TEXT - uma string armazenada usando UTF-8, UTF-16BE ou UTF-16LE. BLOB - armazena um blob, como indica o nome. Uma coluna INTEGER PRIMARY é uma exceção. Só aceita números inteiros. Qualquer valor em um comando SQL tem uma classe de armazenamento implícita. Durante a execução do comando SQL, o SQLite pode converter valores entre classes numéricas (INTEGER e REAL)

Lazarus - Criando relatórios com FortesReport (Parte I)

Para a criação de relatórios, o Lazarus já trás o componente LazReport, no entanto ele precisa ser instalado no IDE. Para fazer a instalação do pacote, acesse o menu Package -> Open package file (.lpk) . Localize o diretório de instalação do Lazarus e na pasta components abra lazreport e depois source . Abra o pacote lazreport.lpk , clique em Compile e depois em Install . Como já sabemos isso irá recompilar o IDE. Depois de inicializado novamente estará disponível a aba LazReport . Leia aqui um tutorial básico sobre o LazReport. No entanto queremos mostrar uma alternativa ao LazReport . Por essa razão, vamos apresentar neste artigo o FortesReport . Para quem conhece o QuickReport, que fazia parte do Delphi, não terá dificuldade de desenvolver com esse componente. Baixe o pacote aqui e instale. Os procedimentos são semelhantes aos que mostramos acima. Você terá uma nova aba chamada Fortes Report . Conectando o banco de dados O primeiro passo para criar a aplicação é fazer