Olá!

Estou de volta para mais um artigo desta série.

Gostaria de lembrar que por enquanto não estou disponibilizando os fontes. Mesmo porque, ainda não temos um código que faça jus o download. OK, confesso: quero que você quebre um pouco a cabeça, forçando a mente a trabalhar, melhorando a assimilação do conteúdo. 😡 Mas não se preocupe, em breve começarei a disponibilizar o link com os fontes.

Ajustes no código já trabalhado

Antes de iniciar, quero falar de uma pequena mudança que fiz no código do artigo anterior. Em Atributos.pas, eu alterei a classe TCampos, que antes era assim:

[sourcecode language=”delphi”]
TCampos = class(TCustomAttribute)
private
FTipo: TFieldTipo;
FPK: Boolean;
public
constructor Create(ATipo: TFieldTipo; APk: Boolean);
function IsPk: Boolean; virtual;
end;
[/sourcecode]

Agora, está assim:
[sourcecode language=”delphi”]
TCampos = class(TCustomAttribute)
public
function IsPk: Boolean; virtual;
end;
[/sourcecode]

Na function IsPK do TCamposPK:

[sourcecode language=”delphi”]
Resul := True;
[/sourcecode]

Na unit Teste.pas, acima da property ID:
[sourcecode language=”delphi”]

public
[TCampoPk]
property Id: Integer read FId write SetId;

[/sourcecode]

Excluí o construtor e os campos internos (FTipo e FPK). O Constructor agora não tem mais parâmetros.

A alteração foi feita para simplificar um pouco as coisas e tirar campos que não estavam sendo utilizados. Como estamos no início, pode ser que eu volte atrás, mas por enquanto vamos levar da maneira que está.

Aqui está o código completo da unit Atributo.pas:
[sourcecode language=”delphi”]
unit Atributos;

interface

uses
Rtti;

type
TNomeTabela = class(TCustomAttribute)
private
FNomeTabela: string;
public
constructor Create(ANomeTabela: string);
property NomeTabela: string read FNomeTabela write FNomeTabela;
end;

TCampos = class(TCustomAttribute)
public
function IsPk: Boolean; virtual;
end;

TCampoPk = class(TCampos)
public
function IsPk: Boolean; override;
end;

implementation

{ TCampos }

function TCampos.IsPk: Boolean;
begin
Result := False;
end;

{ TCampoPk }

function TCampoPk.IsPk: Boolean;
begin
Result := True;
end;

{ TNomeTabela }

constructor TNomeTabela.Create(ANomeTabela: string);
begin
FNomeTabela := ANomeTabela;
end;

end.
[/sourcecode]

Unidade Base

Temos que ter em mente que quanto mais abstrato for, melhor será o nosso ORM. Visto que, devemos tornar o processo de troca de um conjunto de componentes de acesso por outro o mais transparente possível. Vamos lá!

No Delphi, crie uma nova unit:

E salve com o nome de Base.pas.

O que nós queremos é poder ter acesso ao nosso banco de dados (Firebird) utilizando componentes como o IBX, UIB, DbExpress… sem tantos traumas, não é mesmo? Então, esta unit será a nossa base (é mesmo???) para alcançar este objetivo.

Vamos criar nossa primeira classe em Base.pas:

[sourcecode language=”delphi”]
unit Base;

interface

uses Classes;

type
IBaseDados = interface
[‘{9B0F9364-AB16-4C12-B4B7-4E2287840232}’]
end;
[/sourcecode]

Na verdade, é uma interface e tem o objetivo de ser uma interface padrão para todos componentes databases (TUIBDataBase – UIB, TIBDatabase – IBX, etc.). Nela vemos o código GUID (identificador global único [globally unique identifier]) gerado através das teclas Ctrl+Shift+G.

Vamos criar mais uma interface:
[sourcecode language=”delphi”]
ITransacao = interface
[‘{2F1DCA7A-E7F4-4EC3-BDB2-22B99C8CA7DB}’]
end;
[/sourcecode]

Esta interface será utilizada para os componentes “Transactions”, para controle das nossas transações.

Abaixo destas interfaces, vamos inserir um alias:

[sourcecode language=”delphi”]

type
IBaseDados = interface
[‘{9B0F9364-AB16-4C12-B4B7-4E2287840232}’]
end;

ITransacao = interface
[‘{2F1DCA7A-E7F4-4EC3-BDB2-22B99C8CA7DB}’]
end;

TTabela = class(TObject)
end;

[/sourcecode]

TTabela será uma classe sem propriedades e campos por nós definidos (pelo menos, não por enquanto). É claro que ela herda as propriedades e métodos de TObject.

Você pode estar se perguntando: já que não tem diferença para o TObject, o que justifica criar este alias?

Bom, o fato de necessitarmos do alias é que ele será utilizado em várias partes do nosso projeto, hora sendo uma classe pai de alguma outra classe hora sendo um parâmetro. Então, queremos restringir o uso destas classes, ou seja, que o parâmetro seja do tipo TTabela e não de outra classe qualquer derivada de TObject. Entendido? Ok!

Abra a unit Teste.pas. Altere a classe TTeste:

[sourcecode language=”delphi”]
unit Teste;

interface

uses Base, Rtti, Atributos;

type
[TNomeTabela(‘Teste’)]
TTeste = class (TTabela)
private
FHabitantes: Integer;
FDescricao: string;
FRendaPerCapta: Currency;
FId: Integer;
FData: TDateTime;
FEstado: string;
procedure SetData(const Value: TDateTime);
procedure SetDescricao(const Value: string);
procedure SetEstado(const Value: string);
procedure SetHabitantes(const Value: Integer);
procedure SetId(const Value: Integer);
procedure SetRendaPerCapta(const Value: Currency);
public
[TCampoPk]
property Id: Integer read FId write SetId;
property Estado: string read FEstado write SetEstado;
property Descricao: string read FDescricao write SetDescricao;
property Data: TDateTime read FData write SetData;
property Habitantes: Integer read FHabitantes write SetHabitantes;
property RendaPerCapta: Currency read FRendaPerCapta write SetRendaPerCapta;
end;

implementation

{ TTeste }

procedure TTeste.SetData(const Value: TDateTime);
begin
FData := Value;
end;

procedure TTeste.SetDescricao(const Value: string);
begin
FDescricao := Value;
end;

procedure TTeste.SetEstado(const Value: string);
begin
FEstado := Value;
end;

procedure TTeste.SetHabitantes(const Value: Integer);
begin
FHabitantes := Value;
end;

procedure TTeste.SetId(const Value: Integer);
begin
FId := Value;
end;

procedure TTeste.SetRendaPerCapta(const Value: Currency);
begin
FRendaPerCapta := Value;
end;

end.
[/sourcecode]

Veja que agora ela descende de TTabela e não mais de TObject (não diretamente). Adicione a unit Base ao uses.

Pronto, agora que nós temos as interfaces para o database e o transaction, vamos criar um DAO abstrato:
[sourcecode language=”delphi”]
IDaoBase = interface
[‘{D06AAE8D-D5F7-47E7-BF11-E26687C11900}’]

function Inserir(ATabela: TTabela): Integer;
function Salvar(ATabela: TTabela): Integer;
function Excluir(ATabela: TTabela): Integer;

function InTransaction: Boolean;
procedure StartTransaction;
procedure Commit;
procedure RollBack;

end;
[/sourcecode]

Veja que nossa interface declara os métodos básicos de um CRUD (inserção, deleção e salvamento), faltando apenas a recuperação de dados. Implantaremos isso nos próximos artigos da série. Veja também, que temos os métodos de controle das transações:

  • InTransaction: irá verificar se existe transação aberta;
  • StartTransaction: irá iniciar uma nova transação;
  • Commit: irá efetivar as alterações no banco de dados;
  • RollBack: irá cancelar a transação aberta.

Abaixo, código completo de Base.pas:
[sourcecode language=”delphi”]
unit Base;

interface

uses Classes;

type
IBaseDados = interface
[‘{9B0F9364-AB16-4C12-B4B7-4E2287840232}’]
end;

ITransacao = interface
[‘{2F1DCA7A-E7F4-4EC3-BDB2-22B99C8CA7DB}’]
end;

TTabela = class(TObject)
end;

IDaoBase = interface
[‘{D06AAE8D-D5F7-47E7-BF11-E26687C11900}’]

function Inserir(ATabela: TTabela): Integer;
function Salvar(ATabela: TTabela): Integer;
function Excluir(ATabela: TTabela): Integer;

function InTransaction: Boolean;
procedure StartTransaction;
procedure Commit;
procedure RollBack;

end;

implementation

end.
[/sourcecode]

Diagrama atual do nosso projeto:

Chegamos ao fim deste artigo. No próximo, iremos iniciar a criação da classe específica do UIB.

Obrigado e até a próxima!

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *