Software Development Kit
to the Delphi-Win32 and Free Pascal compilers
Home > Wiki > br/OPF

br/OPF

english (en) | português (br)

O framework de persistência do PressObjects é, dentre os frameworks principais, o que exige menos interferência por parte do usuário. Quase tudo o que o framework precisa já está definido no modelo, ou mais precisamente no Metadata das classes de negócio.

No entanto, algumas dicas são essenciais para um bom proveito deste framework.

Contents

Criar o banco de dados

O OPF do PressObjects não envia DDLs diretamente para o banco, nem mesmo cria um novo banco de dados para o usuário, mas auxilia o desenvolvedor criando um script que pode ser executado com o intuito de criar as tabelas, índices, constraints e generators do banco.

Para criar este script:

uses
  PressOPF;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Memo1.Lines.Text := PressOPFService.CreateDatabaseStatement;
end;

Pronto. O método CreateDatabaseStatement criará um bloco de texto que poderá ser executado por um banco de dados.

Esta rotina pode ser otimizada um pouco mais:

uses
  Clipbrd, PressOPF;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Clipboard.AsText := PressOPFService.CreateDatabaseStatement;
end;

Para criar o banco de dados da aplicação, basta colocar esta rotina em um botão ou em uma opção de menu da aplicação. Depois de executado, basta colar em uma caixa de texto do front-end do banco.

Identificadores longos

Todos os objetos de banco de dados criado pelo CreateDatabaseStatement do PressObjects utiliza nomes lógicos, baseados em nomes de tabelas e campos.

No entanto, é comum que algum nome tenha comprimento maior do que o máximo permitido pelo banco de dados. Caso isto ocorra, o método CreateDatabaseStatement irá alertar nas primeiras linhas do script.

Para reduzir o tamanho do nome destes objetos, pode-se optar entre alterar o nome da tabela ou definir um nome curto, usado apenas para nomear tabelas de relacionamento NxN e constraints.

Nome persistente e nome curto

O nome persistente é o nome que a tabela ou o atributo terá no banco de dados, que pode ser completamente diferente do nome usado dentro da aplicação. Para alterar o nome persistente, inclua a opção PersistentName dentro do metadata da classe:

class function TProduto.InternalMetadataStr: string;
begin
  Result := 'TProduto IsPersistent PersistentName="Prod" (' +
   'Nome: String(80);' +
   'Preco: Currency;' +
   ')';
end;

O nome curto é uma alternativa para os casos em que o nome do objeto não é longo, mas o nome de alguns objetos formados através dele, como constraints ou outras tabelas, passam do máximo permitido pelo banco.

Este problema ocorre com mais frequência em campos do tipo Parts e References, quando estes precisam criar uma tabela auxiliar (NxN). Um exemplo:

class function TOrcamentoItem.InternalMetadataStr: string;
begin
  Result := 'TOrcamentoItem IsPersistent (' +
   'Acabamentos: References(TAcabamento) ShortName="Acabs";' +
   ')';
end;

No exemplo acima, o campo continuará com o nome Acabamentos, mas os objetos derivados dele irá utilizar "Acabs" para compor seus respectivos nomes.

Classe do objeto

Todo objeto guardado no banco de dados precisa gravar, junto com ele, o nome de sua classe. Este recurso permite fazer uma busca em uma determinada classe e instanciar os objetos corretamente. Por exemplo:

uses
  PressSession;

...

var
  VList: TPressProxyList;
begin
  VList := PressDefaultSession.OQLQuery('select * from any TContato');
  try

...

VList poderá ter objetos da classe TPessoa ou TEmpresa, todos descendentes de TContato. Veja mais sobre OQL e outros métodos para recuperar objetos do banco de dados no artigo recuperar objetos.

Para tanto o modelo do PressObjects define automaticamente o nome ClassId como o campo que irá guardar esta informação.

Para fazer uso do recurso e evitar uma string não normalizada e com 32 posições em cada tabela, o objeto PressModel possui uma propriedade que permite nomear uma tabela que terá todos os nomes de classe do modelo. Caso esta propriedade seja preenchida, o campo ClassId receberá um Id ao invés do nome da classe.

uses
  PressSubject;

...

initialization
  PressModel.ClassIdStorageName := 'ModelClass';

No exemplo acima, uma tabela com nome ModelClass será criada com dois campos: um Id e o nome da classe.

OID numérico

O OID padrão do modelo do PressObjects é uma string com 32 posições, suficiente para guardar um GUID. GUID é o OID padrão, que será usado caso a aplicação não forneça o nome de um generator, e nem registre uma classe Generator para o OPF.

Para criar um OID numérico, usar um generator do banco de dados e ficar em paz com a identificação dos objetos, basta definir dois itens no PressModel:

uses
  PressSubject,
  PressAttributes;

initialization
  PressModel.DefaultGeneratorName := 'gen_app';
  PressModel.DefaultKeyType := TPressInteger;

Pronto. Caso o metadata definido pelo desenvolvedor não diga nada contrário, ele utilizará gen_app como o nome do generator do OID, e Integer como o tipo de dado da chave.

Veja mais sobre geração de Id.

Proprietário do objeto Parts

Todo atributo Parts faz referência a objetos em outra tabela. Devido o tipo do relacionamento, não é possível listar os objetos sem criar uma terceira tabela, a menos que o objeto Parts saiba quem é seu dono. Vamos a alguns exemplos:

Um objeto da classe TTelefone pode fazer parte de mais de um cadastro ao mesmo tempo. A mesma tabela TTelefone poderá guardar uma lista de telefones do TVendedor, do TCliente e da TFilial.

Como, em princípio, TTelefone não tem um único dono, a única forma de relacionar telefone e cliente é criando uma tabela intermediária. Não se preocupe com isto, o PressOPF faz todo este trabalho por baixo dos panos.

Por outro lado, vamos supor que todos estes objetos pertençam a uma classe que seja herdeira de uma superclasse em comum: TContato. Dentro de TContato existe um atributo chamado Fones, do tipo Parts(TTelefone). Então, neste caso, TTelefone possui apenas um proprietário, o que nos permite eliminar a tabela auxiliar com o seguinte truque:

class function TTelefone.InternalMetadataStr: string;
begin
  Result := 'TTelefone IsPersistent OwnerClass=TContato (' +
   'Tipo: Reference(TTelefoneTipo);' +
   'Numero: TNumeroTelefone;' +
   ')';
end;

A propriedade OwnerClass associa um proprietário para uma classe cuja instância pertença a outro objeto, e elimina a necessidade de tabela auxiliar.

O exemplo acima ainda define outro recurso do PressObjects: atributo do desenvolvedor(TNumeroTelefone). Veja mais sobre este recurso no artigo criando atributos.