Conexão ao Banco de Dados

Firebird

08/12/2003

Uso Firebird 1.5. tenho um Data Módulo com um componente IbDatabase, um componente IbDataSet e um componente IbTransaction todos interligados, agora preciso acessar as tabelas do Banco de Dados. Qual componente uso para enxegar as tabelas nos formulários? Gostaria de usar na forma de TTable, é recomendável?


Amilton/pr

Amilton/pr

Curtidas 0

Respostas

Afarias

Afarias

08/12/2003

|agora preciso acessar as tabelas do Banco de Dados.

Defina um SELECT na propriedade SelectSQL do IBDataSet


|Qual componente uso para enxegar as tabelas nos formulários?

O componente q ´mantem´ os dados é o IBDataSet (ou poderia ser IBQuery)... vc pode ligar a ele um DataSource e ligar seus componentes (DBEdit, DBGrid, etc...) ao DataSource.


|Gostaria de usar na forma de TTable, é recomendável?

NUNCA -- não é uma boa prática com bancos de dados C/S



T+


GOSTEI 0
Amilton/pr

Amilton/pr

08/12/2003

Entendi. Então vou ter um IbDataset para cada tabela que vou fazer a manipulação de dados?
E os componentes IbDatabase e IbTransaction são necessários?
Desculpe pela insistência, é que estou usando pela primeira vez . . .


GOSTEI 0
Afarias

Afarias

08/12/2003

|Entendi. Então vou ter um IbDataset para cada tabela que vou fazer a
|manipulação de dados?

Sim. O IBDataSet mantem os registros de uma consulta SQL (select) em um buffer (inclusive com suporte bi-direcional) e proporciona uma aplicação parecida a um Table


|E os componentes IbDatabase e IbTransaction são necessários?

Sim. O IBDatabase mantem uma conexão com o servidor e a base de dados e o IBTransaction permite q vc controle explicitamente as sua transações (select, update, insert, delete).


|Desculpe pela insistência, é que estou usando pela primeira vez . . .

sem problemas, fórum é pra perguntar, responder, discutir idéias, etc...



T+


GOSTEI 0
Amilton/pr

Amilton/pr

08/12/2003

Legal. Coloquei a instrução Select na propriedade SelectSql e habilitou os campos da tabela. As demais propriedades SQL do DataSet não estão preenchidas; Coloquei os componentes com Active = true, Agora os dbedits ligados ao Datasource do IbDataSet não habilitaram pra digitação e ainda fui apagar um registro e surgiu a mensagem que não pode deletar no DataSet. Como resolvo isso?


GOSTEI 0
Afarias

Afarias

08/12/2003

para poder ´operar´ nos registros trazidos pela sua consulta (select) vc terá q preencher as propriedades ModifySQL, DeleteSQL e InsertSQL do IBDataSet --- isso é fácil pois o IBDataSet possui um assistente para auxiliar na tarefa, faça o seguinte::

1 - clique com o botào direito do mouse no IBDataSet
2 - selecione o menu DataSet Editor...
3 - no form q aparece, vc verá duas listas
4 - na lista da esquerda (key fields) selecione apenas o(s) campo(s) chave de sua tabela
5 - na lista da direita selecione todos os campos
6 - clique no botão GENERATE SQL
7 - clique Ok (fecha)


pronto, aconcelho também q use a propriedade GeneratorField para designar um generator para um código automático (auto-incremental) caso deseje.


T+


GOSTEI 0
Amilton/pr

Amilton/pr

08/12/2003

Muito bom. Funcionou Legal. No caso de precisar usar um campo da tabela para se relacionar com uma chave de outra tabela(relacionamento) daí como seria esse procedimento?


GOSTEI 0
Amilton/pr

Amilton/pr

08/12/2003

Agora os dados são editados(alterados, apagados), no entanto quando abro o formulário novamente eles não foram modificados, ou seja, a tabela não está gravando os dados. Não estão funcionando o Commit e o RollBack, dá a mensagem de identificação não declarada.


GOSTEI 0
Afarias

Afarias

08/12/2003

||No caso de precisar usar um campo da tabela para se relacionar com
|uma chave de outra tabela(relacionamento) daí como seria esse
|procedimento?

vc pode usar JOINS no SelectSQL, mas lembre-se q apenas 1 tabela pode ser alterada (vc pode alterar mais se usar alguns IBUpdateSQL)...

Vc pode ter campos LOOKUP também...

Vc pode estabelecer relacionamentos mestre-detalhe normalmente com outro IBDataSet... (+/- como faria com Tables)



|Não estão funcionando o Commit e o RollBack, dá a mensagem de
|identificação não declarada

qual o seu código e a mensagem de erro original??


T+


GOSTEI 0
Amilton/pr

Amilton/pr

08/12/2003

Botão gravar:
procedure TF_Emp.BitBtn3Click(Sender: TObject);
begin
if (dbedit1.text = ´´) or (dbedit3.text = ´´) then
begin
messagedlg(´Campos não estão devidamente preenchidos. Verifique!´,mtinformation, [mbok],0);
dbedit1.clear;
dbedit1.setfocus;
end
else
begin // Datam é o nome do Data Modulo
try
with Datam.tblmun do // tblmun é o Nome do IbDataSet
Datam.IBDatabase1.startTransction; // Não funciona
Datam.IbDataBase1.ApplyUpdates; // tbém não funciona
DAtam.tblMun.Post;
datam.IBTransaction1.CommitRetaining; // Não grava o registro
// Datam.tblmun.active:=true;
// DAtam.tblMun.refresh;
// Datam.tblMun.Commit; {on success, commit the changes};
DAtam.tblMun.prior; // Volto ao inicio para gravar somente 1 registro
DAtam.tblMun.edit; //insert;
dbedit1.setfocus;
except
Datam.IBTransaction1.Rollback; {on failure, undo the changes}; // tbém não funciona
raise; {raise the exception to prevent a call to CommitUpdates!}
end;
end;
end;

Obs- Primeiro código onde tento gravar um registro com Firebird;


GOSTEI 0
Afarias

Afarias

08/12/2003

|Datam.IBDatabase1.startTransction; // Não funciona

o StartTransaction é na transação, de forma q vc poderia fazer::

Datam.IBTransaction1.StartTransaction;
ou
Datam.tblmun.Transaction.StartTransaction

como está em um bloco WITH Datam.tblmun DO, vc pode simplesmente::

Transaction.StartTransaction;


|Datam.IbDataBase1.ApplyUpdates

Não há necessidade de usar ApplyUpdates -- A não ser q vc resolva realmente usar ChachedUpdates=True (o q não é bom na mairia dos casos) -- se fosse usar seria no IBDataSet::

Datam.tblmun.ApplyUpdates;

ou, no bloco WITH, simplesmente::

ApplyUpdates;


Mas, como disse não há necessidade - vc não está usando CachedUpdates (suponho) ... basta um POST mesmo.


T+


GOSTEI 0
Amilton/pr

Amilton/pr

08/12/2003

Entendi, mas e o Commit, onde entra nessa história?
Vou testar dessa forma, no entanto até agora a forma que realmente gravou os dados foi usando AppyUpdates no evento AfterPost do DataSet.


GOSTEI 0
Afarias

Afarias

08/12/2003

|Entendi, mas e o Commit, onde entra nessa história?

O commit serve para encerrar a transação gravando difinitivamente as alterações realizadas, um exemplo::


with IBDataSet do
begin
  Transaction.StartTransaction;
  try
    Append;
    FieldByName(´tal1´).AsInteger := tal1;
    FieldByName(´tal2´).AsString := tal2;
    Post;
  finally
    Transaction.Commit;
  end;
end;




|Vou testar dessa forma, no entanto até agora a forma que realmente
|gravou os dados foi usando AppyUpdates no evento AfterPost do
|DataSet.

Como disse esqueça o ApplyUpdates. E, se o ApplyUpdates não está dando erro, e a propriedade CachedUpdates = FALSE, então, ATUALIZE JÁ seu IBX, as versões recentes do IBX não deixam isso ocorrer.


T+


GOSTEI 0
Amilton/pr

Amilton/pr

08/12/2003

Posso colocar esse código no botão nPost do Navigator? Existe úm campo código da tabela que é inserido num edit, então preciso recebe-lo no campo da tabela pra poder gravar e se fizer isso nesse botão acusa a mensagem que o campo está vazio, então recebi no evento BeforePost do Dataset. Está correto?


GOSTEI 0
Afarias

Afarias

08/12/2003

|Posso colocar esse código no botão nPost do Navigator?

Não... o código mostra um processo ´completo´ com a abertura da transação, Append, definição dos valores dos campos, POST e commit.


não entendi o resto da mensagem...


T+


GOSTEI 0
Amilton/pr

Amilton/pr

08/12/2003

Tentei dizer o seguinte: Tenho um campo edit no formulário com a propriedade enabled=false.
Então quando gravo o registro quero pegar o número do último registro da tabela e mostrar nesse edit para o usuário ver o código do novo cadastro e ao mesmo tempo gravando esse numero na tabela. Gostaria de fazer isso sem o generator, é possível?


GOSTEI 0
Amilton/pr

Amilton/pr

08/12/2003

td bem, até grava um registro, mas no próximo registro dá a mensagem que a transação está ativa e sempre grava com CommitRetaining. Só com commit fecha a tabela e fica tudo desabilitado. Cara, tá complicado pra simplesmente gravar um registro atrás do outro. Tá F*!!!!


GOSTEI 0
Afarias

Afarias

08/12/2003

É impressão minha ou vc está ´misturando´ as suas questões??? Não faça isso... se ficar misturando as coisas vai dificultar q as pessoas possam colaborar para obter alguma solução para suas questões.


|Gostaria de fazer isso sem o generator, é possível?

SIM, a principio em programação TUDO é possível... o lance é separar o JOIO DO TRIGO!! Se não quer usar Generators tudo bem, mas certifíque-se de conhecer os ´problemas´ envolvidos.


|td bem, até grava um registro, mas no próximo registro dá a mensagem
|que a transação está ativa e sempre grava com CommitRetaining. {...}

Dê um tempo... organize as idéias... vc provavelmente está complicando algo q é muito simples.

Dê uma lidas nas mensagens deste fórum q existem textos completos de como implementar um cadastro simples...

Veja apostilas, algo q tenha um passo a passo, organize suas dúvidas e pergunte cada uma com um objetivo bem definido -- só assim é possível conseguir alguma ajuda em um Fórum de discussão.

E, WATCH OUT!! Cuidado com a linguagem -- este tipo de atitude não é permitida neste fórum, OK!


T+


GOSTEI 0
Amilton/pr

Amilton/pr

08/12/2003

Desculpe pela expressão, acabei me irritando. É que estava acostumado com o Paradox que era muito simples gravar um registro e agora estou estranhando isso.
A questão é essa . . . Simplesmente gravar um registro e mostra-lo num edit via código sem o generator . . .


GOSTEI 0
Afarias

Afarias

08/12/2003

| Simplesmente gravar um registro


crie um banco de dados com uma tabela com a seguinte estrutura:


create table teste1 (
  codigo      integer not null,
  nome       varchar(30) not null,
  endereco  varchar(60),
  telefone    varchar(15),
  primary key pk_teste1 (codigo)
);

create index ix_teste1_nome on teste1 (nome);




crie um novo projeto no Delphi e coloque no form::

1 panel (Align=alTop, Caption=´´)
1 IBDatabase (DefaultTransaction = IBTransaction1, LoginPrompt = False)
1 IBTransaction (DefaultDatabase=IBDatabase1)
1 IBDataSet (Database=IBDatabase1, Transaction = IBTransaction1)
1 DataSource (DataSet = IBDataSet1)
1 dbGrid (Align=alClient, DataSource=DataSource1)
1 dbNavigator (no Panel -- DataSource = DataSource1)


dê um duplo-clique no IBDAtabase e configure::

database = caminho do banco criado anteriormente

clique na opção REMOTE e configure tb:

server = localhost
protocol = tcp
username = sysdba (ou outro usuário)
password = masterkey (a senha do seu usuário)
character set = o character set q vc criou o banco

clique OK

configure ainda no seu IBDatabase a propriedade AllowStreemedConnected = FALSE


agora, dê um duplo-clique no IBTransaction e selecione a opção READ COMMITED, clique OK

vamos configurar então o IBDataSet

na propriedade SelectSQL coloque seu select, ex::

SELECT * FROM TESTE1
WHERE NOME STARTING WITH :par1

agora, clique com o botão direito do mouse no IBDataSet1 e selecione no menu ´Dataset Editor...´

no editor do IBDataSet, na lista a esquerda (key fields) selecione apenas o campo CODIGO, na lista da direita, selecione todos os campos.

clique no botão GENERATE SQL -- nesse momento, observe os SQLs gerados, eles são um bom exemplo de como devem ser! E vc pode notar (e controlar) tudo q vai ocorrer em cada operação.

Clique OK para fechar o assistente.

Agora, dê um duplo-clique no IBDataSet e adicione o campos persistentes (botão direito e selecione o menu ´Add all fields)

bom, coloque agora no PANEL1 um Botão e um Edit.

limpe a propriedade Text do Edit e...
...no botão coloque o caption = ´pesquisar´ e o código no OnClick::

  IBDataSet1.Close;
  IBDataSet1.Params[0].AsString := Edit1.Text;
  IBDataSet1.Open;


e no evento onCreate do seu Form coloque::

try
  IBDatabase1.Connected := True;
except
  ShowMessage(´não foi possível realizar a conexão com o BD´);
end;


e no OnClose ou OnDestroy do form coloque::

try
  if IBTransaction1.InTransaction then
    IBTransaction1.Commit;
  IBDatabase1.Connected := False;
except
  ShowMessage(´erro de comunicação com o BD´);
end;



coloque mais 2 botões no PANEL1 com os captions COMMIT e ROLLBACK, e coloque os códigos no OnClick (respectivamente)::

IBDataSet1.Transaction.CommitRetaining;

e

IBDataSet1.Transaction.RollbackRetaining;


PRONTO!!!

Execute o programa, clique no botão Pesquisar (não vai haver nada) inclua uns registros... clique no botão COMMIT, e etc... vai usando ele (incluir, editar, excluir, etc... etc...)!


|e mostra-lo num edit via código sem o generator

vc devia explicar melhor aqui o q quer fazer... mostrar O QUE?? em um Edit!!

Se vc quer gerar códigos automáticos, crie uma rotina para isso... vc pode ter uma outra query no form com o código:

SELECT MAX(CODIGO) FROM TESTE1;


[ ATENÇÃO ]

NÃO SEI COMO TIVE CORAGEM DE POSTAR O CÓGIGO ACIMA PARA GERAR CÓDIGOS -- POR FAVOR CRIANÇAS NÃO TENTEM ISSO EM CASA (PELO MENOS EM SISTEMAS MULTI-USUÁRIOS) -- SE SEU SISTEMA DER PROBLEMAS (CERTAMENTE VAI OCORRER) -- NÃO ME CULPEM -- JÁ ESTÃO AVISADOS!!! :wink:

[ ******** ]

e pegar o valor retornado na consulta e incrementar!! Onde fazer isso?? Bom, ai é com vc... isso ai já é questão de seu conhecimento de programação e tem a ver com delphi e não com IB


T+


GOSTEI 0
Amilton/pr

Amilton/pr

08/12/2003

Sobre o tópico ´Atenção´ nem vou fazer comentários, pois a ajuda que estou tendo é muito maior.
Como estou usando FB pela primeira vez essa resposta me ajudou muito . . . legal!
Para criar uma autonumeração num campo código fiz uma SQL que encontra o maior número e acrescenta 1 e parece que funcionou, mas minha dúvida é se em rede com dois usuários cadastrando ao mesmo tempo isso vai funcionar bem . . .


GOSTEI 0
Afarias

Afarias

08/12/2003

|Sobre o tópico ´Atenção´ nem vou fazer comentários, pois a ajuda que
|estou tendo é muito maior.

Muitas outras pessoas podem ler este tópico e muitas destas são iniciantes, só não quero correr o risco q alguem tome aquele forma de trabalhar com auto-numeração como algo ´correto´.


|Como estou usando FB pela primeira vez essa resposta me ajudou
|muito . . . legal!

Fico contente.


|mas minha dúvida é se em rede com dois usuários cadastrando ao
|mesmo tempo isso vai funcionar bem . . .

Como já disse:: NÃO VAI FUNCIONAR -- vc vai correr o risco de receber uma violação de chave primária e ter de pegar um novo código -- nada q vc não possa tratar, claro.


T+


GOSTEI 0
Amilton/pr

Amilton/pr

08/12/2003

Muito bem. Posso enteder que a melhor forma seria através de Generator. Esse código retirei daqui mesmo - função:

1-function TFormx.GetNewID(const AGenerator: string): Integer;
2-const
3- SQLText = ´select gen_id(¬s, 1) from rdb$database´;
4-begin
5- with IBSQL1 do
6- begin
7- SQL.Text := Format(SQLText, [AGenerator]);
8- Transaction.StartTransaction;
9- try
10- ExecQuery;
11- Result := Fields[0].AsInteger;
12- finally
13- Transaction.Commit;
14- end;
15- end;
16-end;

Fiz uma numeração de linhas pra mostrar que dá erro na linha 7(acho que o ponto, mas tirei esse ponto e mesmo assim dá erro) e depois na linha 10.
Acredito que agora teria o código da Generator pra rodar com essa função!
Como seria essa sequência de procedimentos e onde faze-los?


GOSTEI 0
Afarias

Afarias

08/12/2003

Bom, eu uso perfeitamente este código (não é a toa q o postei) ;)

Qual a mensagem de erro q vc está recebendo??



T+


GOSTEI 0
POSTAR