Lazarus Tdbf Tutorial/pt

From Free Pascal wiki
Jump to: navigation, search

Deutsch (de) English (en) español (es) français (fr) português (pt) русский (ru) 中文(中国大陆)‎ (zh_CN)

Visão Geral

Este tutorial é sobre o desenvolvimento básico de banco de dados usando o componente TDbf (de Micha Nelissen) no Lazarus. Doumentação adicional para o TDbf está disponível. Esta página foi criada por Tony Maro, mas outros contribuidores são bem-vindos!

Para a documentação em PDF vá ao SourceForge. Isto pode ser útil para manter esse PDF ao lado desta documentação enquanto a lê.

Do que você vai precisar

Sem dúvida logo vai ser mais fácil quando o Free Pascal publicar a próxima versão 2.0, no entanto atualmente você vai precisar de uma edição CVS recente do FPC 1.9.x para usar adequadamente o componente TDbf. Isto pode ser feito baixando só o componente TDbf e usando-o com a versão 1.1 do Free Pascal, mas esta documentação foi escrita com a versão 1.9.x em mente, parcialmente por causa dos reparos no código, para que os componentes de banco de dados pudessem ser usados no Lazarus.

O pacote DbfLaz (versão 0.9.13) é agora instalado por padrão.

O que a TDbf fornece

A TDbf fornece acesso às tabelas de banco de dados do dBase e do FoxPro para Lazarus (e outros). Isto permite ler, escrever e criar tabelas de dBase III+, dBase IIV, Visual dBase VII e FoxPro. Ela faz tudo isso sem precisar de bibliotecas adicionais ou engines de bancos de dados. Simplesmente coloque-a no seu formulário e você vai ter acesso instantâneo a um ambiente de banco de dados multiplataforma. A TDbf funciona em Windows e Linux usando o Lazarus.

Como criar tabelas de banco de dados

Como não existe uma aplicação "Database Desktop" para Lazarus ainda, nós precisamos criar um novo banco de dados por código.

Configurando o caminho

É uma boa idéia dar ao banco de dados da sua aplicação um diretório próprio. Isto simplifica a feitura de backups dos dados. Existem duas maneiras de configurar o caminho. Você pode configurar o caminho completo usando a propriedade FilePathFull ou pode configurar um caminho relativo ao caminho atual da aplicação com FilePath. Por exemplo, configurar FilePath em tempo de execução como "data/" usaria um subdiretório de dados bem abaixo do executável. Configurar a propriedade FilePathFull como "/var/data/" colocaria tudo nesta pasta, ignorando a localização da aplicação.

Escolhendo um nível de tabela ("TableLevel")

Por padrão, a TDbf criará tabelas dBase IV. Enquanto garante compatibilidade muito grande com os outros níveis de tabela, existem características que você pode querer usar que esse nível não possui. Para utilizar campos auto-incrementados, por exemplo, você precisa de um nível de tabela maior. Eles estão listados abaixo:

  • nível 3 - dBase III+;
  • nível 4 - dBase IV;
  • nível 7 - Visual dBase VII;
  • nível 25 - FoxPro.

Você escolhe o tipo de tabela configurando a propriedade nível de tabela ("TableLevel") adequadamente.

Adicionando campos

Criar campos para a sua nova tabela em tempo de execução segue bastante o antigo padrão do Delphi. Uma vez que você tenha configurado as propriedades caminho de arquivo ("FilePath"), nível de tabela ("TableLevel") e nome de tabela "(TableName"), manipule a propriedade definição de campos ("FieldDefs") para configurar a estrutura. Por exemplo:

MyDbf.FilePathFull := '/lugar/em que/meus arquivos/estão';
MyDbf.TableLevel := 7;
MyDbf.TableName := 'customers.dbf'; // observação: a extensão .dbf é realmente necessária?
With MyDbf.FieldDefs do begin
  Add('Id', ftAutoInc, 0, True);
  Add('Name', ftString, 80, True);
End;

Os tipos de campo estão definidos como:

  • ftUnknown
  • ftString
  • ftSmallInt
  • ftInteger
  • ftWord
  • ftBoolean
  • ftFloat
  • ftCurrency (Nível de tabela 25)
  • ftBCD (Nível de tabela 25)
  • ftDate
  • ftTime
  • ftDateTime
  • ftBytes (Nível de tabela 25)
  • ftVarBytes
  • ftAutoInc (Nível de tabela 7 ou 25)
  • ftBlob
  • ftMemo
  • ftGraphic
  • ftFmtMemo
  • ftParadoxOle
  • ftDBaseOle
  • ftTypedBinary
  • ftCursor
  • ftFixedChar
  • ftWideString
  • ftLargeInt
  • ftADT
  • ftArray
  • ftReference
  • ftDataSet
  • ftOraBlob
  • ftOraClob
  • ftVariant
  • ftInterface
  • ftIDispatch
  • ftGuid
  • ftTimeStamp
  • ftFMTBcd

Os tipos em negrito são os que estão implementados atualmente.

Vá em frente e crie-o!

Once you have defined the fields you wish to use in your new table, you can go ahead and create it with:

   MyDbf.CreateTable;

Como adicionar índices a uma tabela

Se sua base de dados for maior do que alguns registros, você deverá ter índices definidos para fazer procuras mais rapidamente. Para mudar a estrutura do índice de uma tabela, precisamos ter o acesso exclusivo à tabela - que nós teríamos ao criar de qualquer maneira.

       MyDbf.Exclusive := True;
       MyDbf.Open;

Agora, nos só temos que adicionar o indice.

       MyDbf.AddIndex('custid', 'Id', [ixPrimary, ixUnique]);
       MyDbf.AddIndex('custname','Name', [ixCaseInsensitive]);
       MyDbf.Close;

Junte tudo e o resultado é...

O fragmento de código a seguir cria uma nova tabela chamada "customers" (clientes) no código. Isso, é claro, precisa ser feito somente uma vez, e depois que você abre uma tabela não precisa criá-la novamente. ;-)

Observação: crie o diretório relativo "data" antes de rodar este exemplo, ou a execução falhará.

{$MODE OBJFPC}
Program DatabaseTest;   
{ Precisaremos que as seguintes unidades estejam na cláusula USES: }
uses Dbf, db, Dbf_Common;                                   
{ A uniadde Dbf é colocada ali quando você põe a TBDF em um formulário. }
{ No entanto, você precisará do banco de dados para o objeto DataSet e de Dbf_Common }
{ para coisas como as definições de campo. }
var
  MyDbf: TDbf;
begin
  MyDbf := TDbf.Create(nil);
  try
    { use o caminho relativo para o diretório "data }
    MyDbf.FilePath := 'data/'; 
    { queremos utilizar tabelas compatíveis com Visual dBase VII }
    MyDbf.TableLevel := 7;
    MyDbf.Exclusive := True;
    MyDbf.TableName := 'customers.dbf';
    With MyDbf.FieldDefs do begin
      Add('Id', ftAutoInc, 0, True);
      Add('Name', ftString, 80, True);
    End;
    MyDbf.CreateTable;
    MyDbf.Open;
    MyDbf.AddIndex('custid', 'Id', [ixPrimary, ixUnique]);
    { add a secondary index }
    MyDbf.AddIndex('custname','Name', [ixCaseInsensitive]);
    MyDbf.Close;
  finally
    MyDbf.Free;
  end;
end;

Arquivos de índice externos

A TDbf também possibilita o armazenamento de índices secundários em um arquivo separado. Isso pode ser útil caso se espere que o banco de dados seja grande. Índices secundários são muito similares aos índices normais, com a adição da extensão de arquivos '.ndx'.

    MyDbf.AddIndex('custname.ndx','Name', [ixCaseInsensitive]);


O índice precisa ser recarregado todas as vezes que a TDdf é aberta.

    MyDbf.OpenIndexFile('custname.ndx');


Além disso, índices precisam ser chamados com o nome completo (incluindo a exntesão).

    MyDbf.IndexName := 'custname.ndx';


Esses arquivos também são empacotados separadamente, usando:

    MyDbf.CompactIndexFile('custname.ndx');

Como ligar a TDbf aos componentes que acessam os dados

Os exemplos abaixo mostram como criar uma nova tabela de banco de dados no código. Usá-la é ainda mais simples.

Esses componentes no Lazarus (como exemplo o controle TDbEdit) se ligam a um componente TDataSource usando suas propriedades "DataSource" e "DataField". O componente TDataSource cuida da comunicação entre o motor (engine) do banco de dados e dos componentes acessados. Uma TDataSource então se liga à TDbf usando sua propriedade "DataSet". A conexão se parece com isso:


TDbEdit-------
             |
TDbEdit------|-->TDataSource-->TDbf
             |
TDbNavigator--


Certifique-se de configurar as propriedades "caminho do arquivo" (FilePath, ou FilePathFull), o "nível da tabela" (TableLevel) e o "nome da tabela" (TableName)da sua TDbf antes de chamá-la.

TDbf.Active := True;

Há muito mais que pode ser dito sobre programar com bancos de dados no Lazarus, e eu recomendaria um ou dois bons livros de programação de banco de dados em Delphi, já que os conceitos por trás disso tudo são os mesmos. Eu constantemente refiro-me à minha cópia de "Delphi 2 Unleashed" [nome do livro em português] porquê os conceitos e o código básico não mudam muito há 8 anos.

Empacotando e reconstruindo as tabelas

Quando um campo é apagado, ele não é de fato removido da tabela física. Periodicamente, você precisa "empacotar" uma tabela para recuperar o espaço perdido. Isso deve ser feito com o modo exclusivo acionado.

MyDbf.Exclusive := True;
MyDbf.Open;
MyDbf.PackTable;
// vamos reconstruir todos os índices também
MyDbf.RegenerateIndexes;
MyDbf.Close;
MyDbf.Exclusive := False;

Relações entre tabelas-mestras

O verdadeiro poder em programar com banco de dados começa quando você tem tabelas múltiplas que chamam umas às outras. Enquanto a TDbf ainda não possui integridade referencial, ela possui uma relação mestre / detalhe entre TDbfs [Última frase confusa].

Um exemplo disso é quando duas tabelas estão interligadas:

[fregueses]
Id       <----| Número de identidade
Name          | Nome
Phone         | Telefone
Address       | Endereço
              |  
[lista de     | O número do freguês em listas de compras ("CustID") faz 
 compras ]    | referência a um campo primário de freguês
Id            | Identidade
Amount        | Quantidade
CustID   -----| [Identidade do freguês?] * Esse último campo é indexado como "idxcustid" 

Se você quisesse mostrar todas as listas de compras para um determinado freguês, a tabela em detalhe (invoices) poderia ficar em sincronia com a tabela-mestra de fregueses (customers) automaticamente.

Nos componentes de listas de compras TDbf, coloque os seguintes valores:

InvDbf.IndexName := 'idxcustid'; // Nosso campo que servirá para pesquisar a tabela
                                 // de identidade dos fregueses.
InvDbf.MasterSource := dsCustomers; // Base de dados ligada aos fregueses em TDbf.
InvDbf.MasterFields := 'Id'; // Campo na tabela dos fregueses que nós usaremos para 
                             // pesquisar no índice.


Como Filtar Datas em Branco com TDbf

Eu estarei mostrando aqui como podemos filtrar as datas em branco com o componente Lazarus TDbf.

Considere-se que, neste exemplo, o componente TDbf é chamado de dados e seu banco de dados tem um campo DT_ENCERRA que indica quando o caso foi concluído. Imagine também que você precisa para criar um relatório usando LazReport que lista todos os casos que ainda estão em aberto (com o campo DT_ENCERRA) em branco.

A maneira mais fácil de fazer isso é usando o evento OnFilterRecord colocando o seguinte código:

if not dadosab.FieldByName('DT_ENCERRA').IsNull then Accept := False;


Quando colocamos o valor do Accept como Falso todos os registros que não satisfaçam essa condição em particular são desconsiderados, ou seja, não são exibidos no relatório.

Também é necessário colocar o banco de dados de propriedade Filtered para true, mas fora desse evento.


Como Filtrar Valores com TDbf

Imagine que você tem um banco de dados que identifique os produtos por um código, por exemplo: B019 e que você precisa filtrar apenas os produtos que são deste código (B019, neste exemplo) para que seja gerado um relatório com LazReport. O componente TDbf é chamado de dados aqui. O campo que armazena o valor chama-se "ID_PRODUTO"

Temos duas formas de filtrar. A primeira delas seria usar o seguinte código:

dados.filter := 'ID_PRODUTO' = "B019"' dados.filtered := true;

Acontece que isso funciona muito bem com vários componentes, mas não funciona com o LazReport.

Para resolver o problema com o LazReport você pode usar o Evento OnFilterRecord e usar o seguinte código:

Accept := Copy(Trim(dadosNot.FieldByName('ID_PRODUTO').AsString),1,4) = 'B019';

É necessário, colcoar-se dados.filtered como true, fora do referido evento.

Como dito antes, quando o valor de Accept é false os registros são desconsiderados e desta forma é possível exibir-se todos os produtos com o referido código no relatório do LazReport.


Amostra de aplicativo - Navegador que utiliza um banco de dados

Escrevi um aplicativo bem simples que usará a TDbf para abrir e mostrar tabelas de bancos de dados usando o controle dbGrid. O executável Linux, junto com o código-fonte dos projetos que provavelmente compilarão bem no Windows estão disponíveis em:

tony.maro.net

Coisas em que você precisa estar atento

Atualmente não há suporte para integridade referencial ou arquivos .dbf internamente codificados.

See also