58
2004 - http://www.liws.com.br/depo

Delphi Persistent Object

Embed Size (px)

Citation preview

Page 1: Delphi Persistent Object

2004 - http://www.liws.com.br/depo

Page 2: Delphi Persistent Object

Índice

0

Introdução 4

................................................................................................................................... 41 Introdução

................................................................................................................................... 42 Apresentação

................................................................................................................................... 43 Sobre o DePO

................................................................................................................................... 54 Instalação

................................................................................................................................... 85 "TODO List" e "Problemas conhecidos"

................................................................................................................................... 86 Material de apoio

Arquitetura 10

................................................................................................................................... 101 Como o DePO funciona

................................................................................................................................... 102 Classes e Propriedades

................................................................................................................................... 123 Units

................................................................................................................................... 124 Declarando Objetos

................................................................................................................................... 135 Mapeamento de Objetos

.......................................................................................................................................................... 13De Objetos para RDB

.......................................................................................................................................................... 15Mapeando Objetos

................................................................................................................................... 176 Sincronizando o banco de dados

Trabalhando com Objetos 20

................................................................................................................................... 201 CRUD

................................................................................................................................... 202 Criando

................................................................................................................................... 203 Recuperando

................................................................................................................................... 214 Alterando

................................................................................................................................... 215 Excluindo

................................................................................................................................... 216 Operações em Cascata

................................................................................................................................... 227 Problemas com Operações em Cascata

................................................................................................................................... 248 Listas (Coleções)

................................................................................................................................... 269 OID

................................................................................................................................... 2710 Generalização

Desenvolvendo Aplicações 31

................................................................................................................................... 311 Relacionamento entre os Objetos

................................................................................................................................... 332 (Re)Utilizando os Objetos

Criando Interfaces para Usuários 36

................................................................................................................................... 361 Interfaces RAD

DePO - Delphi Persistent ObjectsI

© <2004> http://www.liws.com.br/depo

Page 3: Delphi Persistent Object

Técnicas Avançadas 38

................................................................................................................................... 381 Tipos de dados

.......................................................................................................................................................... 38Imagem, Memo

.......................................................................................................................................................... 41Boolean

.......................................................................................................................................................... 42TDateTime

................................................................................................................................... 422 Clonando Objetos

................................................................................................................................... 433 Utilizando Proxy

................................................................................................................................... 444 Critérios para recuperar Objetos

................................................................................................................................... 465 Ordem de recuperação (Sort)

................................................................................................................................... 466 Transações

Extras 49

................................................................................................................................... 491 ModelMaker

História 55

IIConteúdo

II

© <2004> http://www.liws.com.br/depo

Page 4: Delphi Persistent Object

IIntrodução

Page 5: Delphi Persistent Object

Introdução 4

© <2004> http://www.liws.com.br/depo

1 Introdução

1.1 Introdução

AttentionThe job started by Liws aim to work together with brazilian developer, but if you don't knowportuguese, contact us, we will publish english documentation if someone need.

AtençãoO trabalho iniciado pela Liws tem como objetivo atender a comunidade de desenvolvedoresbrasileiros, mas se você não conhece português, entre em contato com a Liws, nós estaremosdisponibilizando materias em Inglês se alguém precisar.

Nota: Esta documento é preliminar e está sujeito a mudanças.

Esta versão esta disponível para que você possa conhecer o funcionamento do DePO e para quepossa contribuir para o desenvolvimento do mesmo.

Se você desejar contribuir com o manual, programas exemplos ou com a melhora do código doDePO entre em contato pelo [email protected].

Um blog está sendo escrito sobre o desenvolvimento do DePO em http://www.liws.com.br/depo atéque uma página oficial seja publicada.

1.2 Apresentação

"A good business model provides a software-independent description of thebusiness processes to beautomated, thereby promoting a good understanding of priorities and risksprior to technology selection." Introduction to Business Modeling Using the Unified Modeling Language (UML)

Conforme este documento da Rational diz, "Um bom modelo de negócios apresenta uma descriçãodos processos de negócio, indentente do software, porém promovendo um bom entendimento dasprioridades e riscos antes da seleção da tecnologia".

Apesar desta afirmação abstrair a tecnologia, se você esta lendo este manual, provavelmente estápensando em utilizar o DePO e o Delphi, assim sendo, vamos a outra visão desta afirmação, umbom modelo, deve ser independente de como será armazenado e independente de como seráapresentado ao usuário final, isto é o que o DePO pretende fazer, disponibilizar uma base para secriar o modelo de negócios, encapsulando todo o comportamento necessário para armazenar erecuperar os dados de fontes de dados diversas.

[Uma imagem apresentando a arquitetura DePO, algo como a que está na documentação daArquitetura do Object Space, precisamos de artistas aqui]

1.3 Sobre o DePO

Delphi Persistent Objects encapsula todo o comportamento necessário para se comunicar com fontesde dados. DePO utiliza um esquema de mapeamento para determinar que campos e tabelas da fonte

Page 6: Delphi Persistent Object

DePO - Delphi Persistent Objects5

© <2004> http://www.liws.com.br/depo

de dados serão mapeados para as propriedades dos objetos. O que significa que campos e tabelasserão utilizados para persistir dados dos objetos, e serão utilizados para popular as propriedades dosobjetos recuperados das fontes de dados.

DePO foi implementado com base no modelo apresentado por Scott Ambler no documento "TheDesign of a Robust Persistent Layer for relational Databases" disponível junto com outrosdocumentos relacionados em http://www.ambysoft.com.

[Incluir a data que o projeto começou]A versão inicial foi implementada por Cosimo de Michele e está disponível emhttp://sourceforge.net/projects/depo, a versão disponível em http://www.liws.com.br/depo difere dadisponível no Source Forge, por algumas correções enviadas pelo Cosimo e algumas alteraçõesimplementadas pelo Liws e seus colaboradores, aconselho que você utilize a vesão disponível pelaLiws.

No momento em que este manual esta sendo escrito (Julho de 2004) a Microsoft está trabalhando nodesenvolvimento de uma camada de persistência chamada ObjectSpace que pelo que sei se parecemuito com a implementação do DePO e tem suas bases no modelo proposto por Scott Ambler, umaleitura na documentação do ObjectSpace pode ajudar a entender os conceitos de uma camada depersistência,http://longhorn.msdn.microsoft.com/lhsdk/ndp/daconoverviewofobjectspacesarchitecture.aspx.

1.4 Instalação

Baixe a última versão do DePO de http://www.liws.com.br/depo/arquivos.

Versões do Delphi suportadas:Esta versão foi testada no Delphi 7, provavelmente você consiga instalar em uma versão anterior dodelphi com poucas alterações, devido as mudanças das uses no delphi.Provavelmente deve funcionar perfeitamente no Kylix 3, você deve apenas remover a unitdpoADOMechanism.pas.

Atenção:Se você tiver uma versão anterior do DePO remova-a do Delphi e apague os arquivos Depo.bpl eDepo.dcp do diretório de Bpl´s, se você usa o Delphi 7 provavelmente ele estará em "C:\Arquivos deprogramas\Borland\Delphi7\Projects\Bpl"

Instalando:1) Decompacte o arquivo deposources.zip Serão criados os diretórios:

SourceLibDoc

2) Abra o pacote Depo.dpk no Delphi Em Options|Diretories/Condicionals define o diretório de Output das Units para o diretórioLib

Page 7: Delphi Persistent Object

Introdução 6

© <2004> http://www.liws.com.br/depo

3) Clique em Compile

4) Clique em Install

Page 8: Delphi Persistent Object

DePO - Delphi Persistent Objects7

© <2004> http://www.liws.com.br/depo

5) Os componentes estarão na paleta DePO6) Para compilar projetos com DePO inclua o diretório Lib no menu Tools|EnvironmentOptions|Library|Library Path

O DePO está pronto para ser usado, aproveite :)

Page 9: Delphi Persistent Object

Introdução 8

© <2004> http://www.liws.com.br/depo

1.5 "TODO List" e "Problemas conhecidos"

Implementar critérios não implementados no DePOTerminar a documentaçãoEscrever novos mecanismos de persistência (XML, Zeos, IBX por exemplo)Criar um site para o DePO

Criar mais exemplos- Relatórios- Web- Outros bancos de dados- com TdpoDataSet

Script para criar o banco de dados- Criar ForeignKey- Campos em sincronismo (Blob, Boolean)- PrimaryKey em Sincronismo

1.6 Material de apoio

Fontes de informações úteisFórum OODesign http://www.oodesign.com.brAmbySoft - Scotty Ambler http://www.ambysoft.comNewsgroup Borland newsgroups.borland.com grupo borland.public.delphi.oodesignMicrosoft ObjectSpacehttp://longhorn.msdn.microsoft.com/lhsdk/ndp/daconoverviewofobjectspacesarchitecture.aspxOMG UML http://www.omg.orgSite oficial do DePO http://sourceforge.net/projects/depoSite do DePO em Português http://www.liws.com.br/depo

Page 10: Delphi Persistent Object

IIArquitetura

Page 11: Delphi Persistent Object

Arquitetura 10

© <2004> http://www.liws.com.br/depo

2 Arquitetura

2.1 Como o DePO funciona

DePO armazena, recupera e exclui objetos em bancos de dados, todo o trabalho necesaário paraque estas tarefas sejam executadas são feitos automaticamente pelo DePO.

O DatabaseMechanism é a implementação basica da interface necessária para que este trabalhoseja feito, todo a interação com este mecanismo deve ser feita através dos mecanismos específicospara a conexão com o banco de dados, atualmente estão implementados os mecanismosADOMechanism para comunicação utilizando ADOConnection e DBXMechanism para comunicaçãoutilizando SQLConnection do DBExpress.

ApósDePO is able to take care itself in automatic way of the creation, loading, modernization andcancellation of objects. The objects do not have no acquaintance which it is the source or thedestination of the contained information in their attributes. Different objects can recover their datafrom different sources, and the destination can be changed where persist the data changing with littlelines of code.

Once that has been written the way in which the information must persist (the persistencemechanism), all the the one which is necessary to make in order to persist objects are to mapping theclasses and the attributes with the properties of the persistence mechanism, as an example the tablesand the columns that will contain the data for the mechanisms that they have to that to make with thedatabase relational.

DePO can also persist inherited classes, persistindo the differences from the class base in connectedtables. In this way it is possible to see the property common of different classes that they derive fromthe same class. In other words I can have a list of customers and suppliers in the same grill, and if Iwant to modify one of these objects, I can make creating it the correct associated type of form theclass.

DePO manages in way the many simple relations between objects and the persistence of theserelations conserving referencial integrity. All the classes of our colloquiano model with the mechanismof persistence or the mechanisms of persistence demanding the operation that they want to carry outthrough an object arbitrator the PersistenceManager, that knowing all the present mechanisms andthe mappings to they it associates to you will turn the operation demanded from the class to theinterested mechanism of persistence.

2.2 Classes e Propriedades

A declaração das classes é como de qualquer objeto no delphi com a seguinte particularidade, DePOutiliza a RTTI do Delphi para poder acessar as propriedades publicadas.

Segundo o Delphi, e como consta no manual do tiOPF:

TPersistent encapsula o comportamento comum para todos os objetos serem acessados por outrosobjetos, e que podem ler e gravar suas propriedades de e para Stream. Por este propositoTPersistent introduz métodos que poder ser sobrescritos para:Definir a procedure para carregar e armazenar dados não publicados para um stream.Prover um meio para acessar os valores das propriedades.Prover um meio para acessar o conteúdo de um objeto para outro.

Page 12: Delphi Persistent Object

DePO - Delphi Persistent Objects11

© <2004> http://www.liws.com.br/depo

{$M+} TPersistent = class(TObject) private procedure AssignError(Source: TPersistent); protected procedure AssignTo(Dest: TPersistent); virtual; procedure DefineProperties(Filer: TFiler); virtual; function GetOwner: TPersistent; dynamic; public destructor Destroy; override; procedure Assign(Source: TPersistent); virtual; function GetNamePath: string; dynamic; end;{$M-}

A diretiva de compilação $M, ativa antes de TPersistent e desavida após, faz com que a geração deinformações RTTI (Run Time Type Information) ocorra para TPersistent e todas as classesderivadas de TPersistent.

TdpoPersistentObject = class(TInterfacedPersistent, IdpoPersistentObject)

A classe TdpoPersistentObject é derivada de TInterfacedPersistent que por sua vez é derivada deTPersistent.

Para que o DePO possa popular as propriedades de uma classe automaticamente, esta deve serderivada de TPersistent ou ser compilada com a diretiva $M ativada ou derivada de outra que estejacom RTTI ativada. Mas não basta ser derivada de TPersistent é necessário que estas propriedadesestejam publicadas, ou seja na sessão published da classe, como no exemplo a seguir:

type TPerson = class(TdpoPersistentObject) private FChields: TdpoRelationshipResolver; FName: String; FFatherOID: String; FID: String; function GetChields: TPeople; function GetHasChields: Boolean; public procedure AfterConstruction; override; property HasChields: Boolean read GetHasChields; published property ID: String read FID write FID; property Name: String read FName write FName; property FatherOID: String read FFatherOID write FFatherOID; property Chields: TPeople read GetChields; end;

Na classe TPerson, DePO só terá conhecimento das propriedades ID, Name, FatherOID e Chields, apropriedades HasChields, apesar de pública, não será acessivel pelo DePO, pois RTTI só contéminformações published.

Page 13: Delphi Persistent Object

Arquitetura 12

© <2004> http://www.liws.com.br/depo

2.3 Units

dpoIntrospector in 'dpoIntrospector.pas',

dpoDatabaseSchema in 'dpoDatabaseSchema.pas', dpoClassMapping in 'dpoClassMapping.pas',

dpoPersistanceObject in 'dpoPersistanceObject.pas',

dpoDatabaseMechanism in 'dpoDatabaseMechanism.pas', dpoADOMechanism in 'dpoADOMechanism.pas', dpoDBXMechanism in 'dpoDBXMechanism.pas';

dpoDataSet in 'dpoDataSet.pas';

dpoRegister in 'dpoRegister.pas',

2.4 Declarando Objetos

Os objetos devem ser declarados como qualquer objeto no Delphi, mas o DePO apresenta duasclasses básicas para facilitar o trabalho, implementando várias propriedades e métodos.

A seguir alguns exemplos de mapeamento de objetos e lista de objetos.

TCliente = class(TdpoPersistentObject) private FEmails: TdpoRelationshipResolver; published property ID: String read FID write SetID; property Nome: String read FNome write SetNome; property Emails: TEmails read GetEmails; end;

TEmails = class(TdpoPersistentObjectList) public function Add: TEmail; property Items[const Index: Integer]: TEmail read GetItem; default; end;

TEmail = class(TdpoPersistentObject) published property ID: String read FID write SetID; property Endereco: String read FEndereco write FEndereco; property Cliente: TCliente read GetCliente write SetCliente; property ClienteOID: String read FClienteOID write FClienteOID; end;

Page 14: Delphi Persistent Object

DePO - Delphi Persistent Objects13

© <2004> http://www.liws.com.br/depo

2.5 Mapeamento de Objetos

2.5.1 De Objetos para RDB

Conceitos Fundamentais de Mapeamento de objetos para banco de dados relacionais, porMarcos Barreto

A maioria das modernas aplicações é projetada para o uso da tecnologia orientada a objeto e bancosde dados de relacionais (RDBs) para armazenar os dados. Isto não que dizer que não haja outrasopções, é por que existem muitas aplicações construídas com linguagens procedurais e muitossistemas usarão bancos de dados orientados a objeto ou arquivos XML para armazenar os dados.Há uma incompatibilidade (impedance mismatch) entre a tecnologia orientada a objeto e arelational, tecnologias estas que são geralmente usadas para construir os softwares. É muito fácilsuperar esta incompatibilidade, o segredo é: você precisa entender o processo de mapeamento deobjetos para RDBs e você precisa entender como implementar estes mapeamentos. Neste capítuloo termo "mapeamento" será usado para fazer referência a como um objeto e seus relacionamentospodem ser mapeados para uma tabela e seus relacionamentos no banco de dados. Logo vocêdescobrirá que a coisa não é tão simples como soa.Conceitos BásicosQuando aprendendo a mapear objetos para RDB's o ponto inicial para começar é com os atributos deuma classe. Um atributo será mapeado para zero ou mais colunas em um RDB. Lembre-se quenem todos os atributos são persistentes, alguns são usados para cálculos temporários. Por exemplo,um objeto "Estudante" pode ter um atributo Media que é necessário dentro de sua aplicação mas nãoé necessário ao banco de dados porque ele é calculado pela aplicação. Outra questão é que umatributo de uma classe pode ser também uma outra classe (Classe complexa), temos como exemploum objeto "Cliente" tem um objeto "Endereço" como um atributo - isto realmente reflete umaassociação entre as duas classes que precisaria ser provável mapeada, e os atributos da própriaclasse "TEndereço" precisarão ser também mapeados. O mais importante é que tudo isto é umadefinição recursiva: Em algum ponto o atributo será mapeado para zero ou mais colunas.A mapeamento mais fácil que você terá é uma propriedade mapeada de um simples atributo a umasimples coluna. É até mais simples quando ambos tem os mesmos tipos básicos, por exemplo: elassão ambas datas, o atributo é uma string e a coluna é um char, ou o atributo é um número e a colunaé um float.Pode ser mais fácil pensar que classes são mapeadas em tabelas, e de certo modo elas são, masnem sempre isso acontece de forma direta. Com exceção de bancos de dados muito simples vocênunca terá um mapeamento um-para-um de classes para tabelas, isto será visto neste capítuloquando for visto o mapeamento de heranças.A medida que for explicando sobre mapeamento darei exemplo de como isto é feito no DePO. Todosos exemplos estarão disponíveis no diretório DePO\Demos e para simplificar somente será mostradoaqui o código realmente necessário para demonstrar a parte de mapeamento do framework.

Vou colocar este código aqui no lugar assim que tiver montado os outros exemplos.

Vamos começar com um simples exemplo que fará o mapeamento de um objeto para uma tabela.Simples exemplo de mapeamento no DepoNeste exemplo nós temos uma classe chamada TArtigo que é mapeado para uma tabela chamadaARTIGO e os atributos também são mapeados diretamente para campos um a um. Vamos a classe:

TArtigo = class(TdpoPersistentObject) private FOID: string; FNome: string; FPreco: extended; published property OID: string read FOID write FOID; property Nome: string read FNome write FNome;

Page 15: Delphi Persistent Object

Arquitetura 14

© <2004> http://www.liws.com.br/depo

property Preco: extended read FPreco write FPreco; end;

Veja que todos os atributos estão published, isto porque o framework usa o Delphi RTTI (RunTimetype information) para recuperar os dados contidos nos atributos quando estiver persistindo. Vejaagora o mapeamento:

procedure TAppManager.InitializeModel;begin... with MappingManager.Classes.Add do begin ClassObject:= TArtigo; StorageName:= 'ARTIGO'; with AttributesMapping do begin Add('OID', 'OID', 38, True); Add('Nome', 'NOME', 50).Required:= True; Add('Preco', 'PRECO'); end; end;...end;

Como você pode perceber é bem simples. O método Add, como ele está sendo chamado aqui,retorna um objeto do TdpoDBAttributeMapping e tem como parâmetros:

function TdpoDBAttributeMappingCollection.Add(AAttributeName, AColumnName: String; ASize: Integer = 0; AIsOID: Boolean = False):TdpoDBAttributeMapping;

Exemplo: Depo\Demos\01-Mapping_BasicMapeamento com associação 1-1Como um exemplo deste simples tipo de associação nós escolhemos criar uma nova classechamada TGrupo e então fazer com que TArtigo tenha uma referência a esta classe.Esta associação só é navegável do Artigo para seu Grupo. Ambas as classes são modeladas noseguinte diagrama de classe (este diagrama não mostra métodos propositalmente por não serrelevante ao processo de mapeamento).

Diagrama aqui

Algumas coisa no exemplo ainda estão obscuras assim que verificar detalharei o resto da parte demapeamento.

Mapeando Estruturas de herançaMapeando uma hierarquia para uma simples tabelaMapeando cada classe concreta para sua própria tabelaMapeando cada classe para sua própria tabelaMapeando Classes para uma estrutura de uma Tabela genéricaMapeando herança múltiplaComparando as estratégias

Mapeando relacionamentos de objetosTipos de relacionamentos

Page 16: Delphi Persistent Object

DePO - Delphi Persistent Objects15

© <2004> http://www.liws.com.br/depo

One-to-one, One-to-many, Many-to-manyUni-directional, Bi-directional

Como os relacionamentos de objetos são implementadosComo os relacionamentos do RDB são implementadosMapeando coleções ordenadasMapeando relacionamentos recursivosAjuste de peformanceAjustando seus MapeamentosConsultas por demanda (Lazy Reads)

2.5.2 Mapeando Objetos

O objeto que armazena o mapeamento de classes, atributos e seus relacionamento éTdpoDBMappingManager

var MappingManager: TdpoDBMappingManager;

dpoDBMM:= TdpoDBMappingManager.Create(Self);

O mapeamento pode ser feito diretamente na IDE do Delphi ou através de código, o exemplo aseguir utiliza as classes apresentadas no tópico Declarando Objetos para mostrar o mapeamentovia código.

A classe TCliente possui a propriedade TEmail, vejamos a seguir o mapeamento destas classes:

with MappingManager.Classes.Add do begin ClassObject:= TCliente; StorageName:= 'CLIENTE'; with AttributesMapping do begin Add('Id', 'ID', 38, True); Add('Nome', 'NOME', 50).Required:= True;

with RelationshipsMapping.Add do begin RelatedClass:= TEmail; MasterAttribute:= 'Emails'; IsRetrieveCascaded:= True; IsSaveCascaded:= True; IsDeleteCascaded:= True; Bindings.Add('Id=ClienteOID'); end; end;

with MappingManager.Classes.Add do begin ClassObject:= TEmail; StorageName:= 'EMAIL'; with AttributesMapping do begin Add('Id', 'ID', 38, True); Add('Endereco', 'ENDERECO', 50).Required:= True; Add('ClienteOID', 'IDCLIENTE', 38).Required:= True; end;

12

Page 17: Delphi Persistent Object

Arquitetura 16

© <2004> http://www.liws.com.br/depo

with RelationshipsMapping.Add do begin Cardinality:= OneToOne; RelatedClass:= TCliente; MasterAttribute:= 'Cliente'; Bindings.Add('ClienteOID=Id'); end; end;

with MappingManager do begin RegisterList(TEmail, TEmails); end;

O mapeamento via IDE do Delphi funciona da mesma forma, mas os valores devem ser informadosno Object Inspector com a seguinte particularidade, as propriedades ClassObject eInheritsMappingFrom são do tipo TClass e o Object Inspector não tem como saber quais as classesque estão declaradas em código, para isto foram criadas as propriedades ClassObjectName eInheritsMappingFromName que são do tipo String, que quando definida utiliza o método FindClasspara procurar a classe, o problema é que para que a classe deve ser registrada antes, na sessãoInitialization da unit:

Initialization RegisterClasses([TCliente, TEmail, TEmails]);

ou

Initialization RegisterClasse(TCliente); RegisterClasse(TEmail); RegisterClasse(TEmails);

Antes de começar a utilizar estas classes, é necessário tomar cuidado, pois qualquer referência a.Classes[Index] no evento OnCreate de um Form ou DataModule irá resultar em uma excessão, poisneste momento o Delphi ainda não carregou os objetos armazenados no Form, no método OnShowestes objetos já estarão disponíveis.

Na imagem a seguir a classe TCliente está informada no Object Inspector:

Page 18: Delphi Persistent Object

DePO - Delphi Persistent Objects17

© <2004> http://www.liws.com.br/depo

2.6 Sincronizando o banco de dados

Sincronizando os objetos através do mapeamento com o banco de dados relacional, o métodoApplySchemaInfo do TdpoCustomMechanism, criará as instruções SQL necessárias para sincronizaro danco de dados de acordo com o modelo.

O método a seguir mostra como sincronizar o banco de dados com o modelo:

procedure __InitializeDatabase;var SInfoDB: TSchemaInfoTables; lPos: Integer; lStrings: TStrings;

procedure __ExecuteSQL(Value: String); var lStr: String; begin lStr:= Trim(StringReplace(Value, #$D#$A, '', [])); if lStr <> '' then TdpoDBXMechanism(DBMechanism).DBXConnection.ExecuteDirect(lStr); end;begin SInfoDB:= TSchemaInfoTables.Create(TSchemaInfoTable); TdpoDatabaseMechanism(DBMechanism).Driver.GetSchemaInfo(SInfoDB);

if SInfoDB.Count = 0 then begin if (MessageBox(0, 'Deseja criar o Banco de dados?', 'Atenção', MB_ICONQUESTION or MB_YESNO) = idYes) then begin lStrings:= TStringList.Create; try TdpoDBXMechanism(DBMechanism).ApplySchemaInfo(lStrings); lPos:= 1;

Page 19: Delphi Persistent Object

Arquitetura 18

© <2004> http://www.liws.com.br/depo

while lPos > 0 do __ExecuteSQL(__StrGetToken(lStrings.Text, ';', lPos)); finally lStrings.Free; end; end; end;end;

Aproveitando as informações disponíveis em TSchemaInfoTables se precisarmos saber seapenas uma tabela existe no banco de dados podemos utilizar o método FindTableByName:

if SInfoDB.FindByTableName('Nome_da_Tabela') <> nil then MessageDlg('Tabela existe :)', mtInformation, [mbOK], 0);

Page 20: Delphi Persistent Object

IIITrabalhando com Objetos

Page 21: Delphi Persistent Object

Trabalhando com Objetos 20

© <2004> http://www.liws.com.br/depo

3 Trabalhando com Objetos

3.1 CRUD

Todas as operações que podem ser feitas em um objeto em relação a persistência recebe o nome deCRUD que significa Criar, Recuperar, Atualizar e Excluir (Created, Retrive, Update and Delete). Umainstância de um objetoé identificada unicamente por uma "Identificação de Objeto" conhecida comoOID, o tipo de OID deve ser escolhido entre os tipos disponíveis, você pode utilizar uma string de 38posição com uma GUID, que pode ser gerada pelo Delphi.

Todos os métodos CRUD são implementados em TdpoPersistentObject ou no Mecânismo dePersistência.

3.2 Criando

Supondo que temos a seguinte classe:

type TCliente = class(TdpoPersistentObject) private FID: String; FNome: String; procedure SetID(Value: String); procedure SetNome(const Value: String); public procedure AfterConstruction; override; published property ID: String read FID write SetID; property Nome: String read FNome write SetNome; end;

Portanto se desejamos criar um novo cliente, o seguinte código é suficiente:

var Cliente: TCliente;begin lCliente:= TCliente.Create(DBMechanism); Cliente.Nome:= 'Agostinho Francisco'; Cliente.Save;

O método Save irá tornar este objeto persistente. Note que não passamos nenhum parâmetro para apropriedade ID, a propriedade ID será comentada num capitulo exclusivo sobre OID.

3.3 Recuperando

Para recuperarmos um objeto, após criá-lo, passamos

var Cliente: TCliente;begin

Page 22: Delphi Persistent Object

DePO - Delphi Persistent Objects21

© <2004> http://www.liws.com.br/depo

Cliente:= TCliente.Create(DBMechanism); Cliente.ID:= '{86EAD56F-0D6C-4913-91CB-9E2B1DA54C3E}'; if not Cliente.Retrieve then begin MessageDlg('Cliente não existe', mtWarning, [mbOK], 0); end;

O código acima recupera o objeto com o OID igual a '{86EAD56F-0D6C-4913-91CB-9E2B1DA54C3E}', o método Retrieve quando retorna "True" ou "False", como resultado.

3.4 Alterando

Para recuperarmos um objeto, após criá-lo, passamos

var Cliente: TCliente;begin Cliente:= TCliente.Create(DBMechanism); Cliente.ID:= '{86EAD56F-0D6C-4913-91CB-9E2B1DA54C3E}'; if Cliente.Retrieve then begin Cliente.Nome:= 'Agostinho Francisco Barbosa'; Cliente.Save; end;

Após recuperar um objeto, podemos alterar suas propriedades e salvar novamente.

3.5 Excluindo

O método Delete marca o objeto para ser excluído a exclusão ocorre quando o método Save échamado.

var Cliente: TCliente;begin Cliente:= TCliente.Create(DBMechanism); Cliente.ID:= '{86EAD56F-0D6C-4913-91CB-9E2B1DA54C3E}'; if Cliente.Retrieve then begin Cliente.Delete; Cliente.Save; end;end;

3.6 Operações em Cascata

Se uma classe possui relacionamento com outras, seja OneToOne ou OneToMany, quando estaclasse for acessada, o DePO automaticamente propagar esta operação a todas as classesrelacionadas.

Antes precisamos informar ao DePO que ele deve fazer isto no mapeamento das classes, veja otópico Mapeando Objetos para mais detalhes desta característica.15

Page 23: Delphi Persistent Object

Trabalhando com Objetos 22

© <2004> http://www.liws.com.br/depo

Primeiro Mapeamos a classe TCliente seus atributos e o relacionamento com TEmail, e DePOis omesmo de TEmail para TCliente. Após entender todo o contexto, a parte de código a seguir é ainformação que o DePO necessita para recuperar, salvar e excluir todos os emails quando estasoperações forem executadas em TCliente.

with RelationshipsMapping.Add do begin RelatedClass:= TEmail; MasterAttribute:= 'Emails'; IsRetrieveCascaded:= True; IsSaveCascaded:= True; IsDeleteCascaded:= True; Bindings.Add('Id=ClienteOID'); end; end;

A propriedade Emails, possui o método de leitura GetEmails este método se encarregara de retornartodos os emails do cliente, mas isto só acontecerá se você acessar a propriedade Emails, senenhuma referência a Emails for feita durante o contexto em que Cliente existir. Quando a operaçãofor recuperar ou salvar, isto otimiza o processo, evitando o trafego de informação desnecessária,mas se a operação for exclusão, como se trata de objetos, se os objetos relacionados não foramacessados DePO não terá conhecimento de sua existência e não poderá excluí-los, isto torna aexclusão mais lenta pois primeiro precisamos recuperar os registros, marcá-los para exclusão (isto épropagado automaticamente) e em seguida concluir a operação com Save.Uma implementação de uma propriedade ou método alternativo para que o DePO gere apenasinstruções SQL de exclusão e envie para que o servidor processe, dentro da mesma transação éuma boa alterativa.

Atenção

Apesar de definir algumas propriedades para recuperar, salvar e excluir em cascata, algumasparticularides são características do DePO:

· OneToOne implementadas entre "Objeto - Atributo", mesmo definindo IsRetrieveCascated osdados da classe relacionada serão recuperadas

· OneToOne em Generalização, exemplo:TCliente = class(TPessoa)IsRetrievedCascated em TCliente define se os dados de TPessoa será recuperado ou não.

· OneToMany IsRetrievedCascated define se os dados da classe detalhe será recuperado ou não.

3.7 Problemas com Operações em Cascata

Para os métodos:

TPai.Filhos;TPai.Delete; //não estava apagando os filhos na tabelaTPai.Save;

Se alguma operação não funciona, então provavelmente deve estar faltando alguma coisa no seucódigo:

1) você criou a propriedade filhos no pai?

FFilhos: TdpoRelationshipResolver;

Page 24: Delphi Persistent Object

DePO - Delphi Persistent Objects23

© <2004> http://www.liws.com.br/depo

2) No After construction vc criou o objeto?

procedure TPai.AfterConstruction;begin inherited; FFilhos:= Relationships.Add('Filhos');end;

Atenção:É comum quando adicionar os relacionamentos digitar nomes errados como:

type TInvoice = class(TdpoPersistentObject) private FItems: TdpoRelationshipResolver; public procedure AfterConstruction; override; published property Items: TItems read GetItems; end;

...

procedure TInvoice.AfterConstruction; override;begin inherited; FItems:= Relationships.Add('Itens');end;

A propriedade foi declarada como "Items" e no relacionamento foi passado o texto "Itens"

3) Na coleção de Filhos vc implementou o método GetFilhos com todos os detalhes?

function TPai.GetFilhos: TFilhos;begin if FFilhos.RelatedObject = nil then begin FFilhos.RelatedObject:= TFilhos.Create(DBMechanism, Self, TFilho); FFilhos.Retrieve; end;

Result:= TFilhos(FFilhos.RelatedObject);end;

4) No mapeamento da classe pai você definiu o relacionamento, como IsRetrieveCascated?

with MappingManager.Classes.Add do begin ClassObject:= TPai; StorageName:= 'TABPAI';

with RelationshipsMapping.Add do begin RelatedClass:= TFilho;

Page 25: Delphi Persistent Object

Trabalhando com Objetos 24

© <2004> http://www.liws.com.br/depo

MasterAttribute:= 'Filhos'; IsRetrieveCascaded:= True; IsSaveCascaded:= True; IsDeleteCascaded:= True; Bindings.Add('Id=PaiOID'); end;

5) No mapeamento do Filho, vc criou o campo em que o ID do pai será salvo para que ele possarecuperar?

with MappingManager.Classes.Add do begin ClassObject:= TFilho; StorageName:= 'TABFILHO';

lAttribute:= Add; with lAttribute do begin AttributeName:= 'PaiOId'; ColumnName:= 'PAIOID'; Size:= 38; end; end;

6) No mapeamento do filho, criou o relacionamento com o pai?

with RelationshipsMapping.Add do begin Cardinality:= OneToOne; RelatedClass:= TPai; MasterAttribute:= 'ID'; IsSaveCascaded:= False; IsDeleteCascaded:= False; IsRetrieveCascaded:= False; Bindings.Add('PaiOID=Id'); end;

Note aqui que neste relacionamento os ...cascated são falsos e a inversão dos campos no Binding.....

7) na Interface do Filho a propriedade com o pai?

TFilho = class(TdpoPersistentObject) private ... FPaiOID: String; public ... property PaiOID: String read FPaiOID write FPaiOID; end;

3.8 Listas (Coleções)

Com as classes criadas a partir de TdpoPersistentObjectList podemos gerenciar coleções de objetos,esta classe será o "Interator" para acessar cada um dos objetos que compõe a lista.

Page 26: Delphi Persistent Object

DePO - Delphi Persistent Objects25

© <2004> http://www.liws.com.br/depo

A interface da classe TClientes, será utilizada para acessarmos cada um dos TCliente.

interface

type TClientes = class(TdpoPersistentObjectList) private function GetItem(const Index: Integer): TCliente; reintroduce; public property Items[const Index: Integer]: TCliente read GetItem; default; function Add: TCliente; reintroduce; function New: TObject; reintroduce; end;

implementation

function TClientes.Add: TCliente;begin Result:= TCliente(inherited Add);end;

function TClientes.GetItem(const Index: Integer): TCliente;begin Result:= TCliente(inherited GetItem(Index));end;

function TClientes.New: TObject;begin Result:= TCliente.Create(DBMechanism, Father);end;

Note que na implementação os métodos utilizados Add e New para acrescentarmos mais clientes acoleção e a propriedade "Items", para interagirmos com os itens. A propriedade "Items" deve serutilizada como qualquer coleção de objetos que temos no Delphi como as colunas de uma DBGrid.

Associando Listas com seus Objetos e registrando Listas

PersistentObjectList:

TArtigos = class(TdpoPersistentObjectList) private function GetItem(const Index: Integer): TArtigo; reintroduce; public function Add: TArtigo; function New: TObject; reintroduce; property Items[const Index: Integer]: TArtigo read GetItem; default; end;

PersistentObject:

TArtigo = class(TdpoPersistentObject) public procedure AfterConstruction; override;

Page 27: Delphi Persistent Object

Trabalhando com Objetos 26

© <2004> http://www.liws.com.br/depo

published property OID: string read FOID write FOID; property Nome: string read FNome write FNome; property Preco: Extended read FPreco write FPreco; end;

Registrando a lista:

MappingManager.RegisterList(TArtigo, TArtigos);

3.9 OID

Por que utilizar OID? Por que utilizar GUID?No documento de Scott Ambler em http://www.agiledata.org/essays/mappingObjects.html procure por"The importance of OIDs" "A importância dos OIDs".

Cada classe deve ter uma propriedade definida como OID, não há padrão para o nome dapropriedade e nem da coluna do banco de dados, no mapeamento você deve identificar quaispropriedades serão OID através da propriedade IsOID.

with MappingManager.Classes.Add do begin ClassObject:= TPerson; StorageName:= 'PERSON_TABLE'; with AttributesMapping do begin lAttribute:= Add; with lAttribute do begin AttributeName:= 'Id'; ColumnName:= 'OID_Key'; IsOID:= True; IndexType:= idxUnique; Size:= 38; Required:= True; end; end;

Mesmo quando definido qual propriedade será OID, o valor deve ser atribuido manualmente, vocêpode informar este valor antes de salvar o objeto ou utilizar o Evento OnNewObjectID doTdpoDBMappingManager.

Definindo OID manualmente:

var Pessoas: TPessoas;begin with Pessoas.Add do begin ID:= 1; Name:= 'John Doe'; Save end;end;

Definindo OID no evento OnNewObject ID:

Page 28: Delphi Persistent Object

DePO - Delphi Persistent Objects27

© <2004> http://www.liws.com.br/depo

var dpoDBMM: TdpoDBMappingManager;

procedure TfdmData.DataModuleCreate(Sender: TObject);begin dpoDBMM:= TdpoDBMappingManager.Create(Self);

with dpoDBMM do begin Name:= 'dpoDBMM'; OnNewObjectId:= dpoDBMMNewObjectId; end;end;

procedure TfdmData.dpoDBMMNewObjectId(Sender: TdpoClassMapping; KeyAttribute: TdpoAttributeMapping; var NewObjectId: Variant);var Guid: TGUID;begin CreateGUID(Guid); NewObjectId:= GuidToString(Guid);end;

3.10 Generalização

DePO torna as operações para classes generalizadas transparentes para suas classes básicas, estecomportamento é útil quando derivamos uma classe de outra e criamos uma nova tabela no bancode dados para armazenar somente as informações relacionadas a esta nova classe.

Exemplo:

TPessoa = class(TdpoPersistentObject) published property ID: String read FID write FID; property Nome: String read FNome write FNome; end;

TCliente = class(TPessoa) published property LimiteDeCredito: Currency read FLimiteDeCredito writeFLimiteDeCredito; end;

A classe TCliente é uma generalização de TPessoa, a seguir o mapeamento destas classes:

with MappingManager.Classes.Add do begin ClassObject:= TPessoa; StorageName:= 'PESSOA'; with AttributesMapping do begin lAttribute:= Add; with lAttribute do begin AttributeName:= 'Id';

Page 29: Delphi Persistent Object

Trabalhando com Objetos 28

© <2004> http://www.liws.com.br/depo

ColumnName:= 'OID'; IsOID:= True; IndexType:= idxUnique; Size:= 38; Required:= True; end;

lAttribute:= Add; with lAttribute do begin AttributeName:= 'Nome'; ColumnName:= 'NOME'; Size:= 50; Required:= True; end; end; end;

with MappingManager.Classes.Add do begin ClassObject:= TCliente; InheritsMappingFrom:= TPessoa; StorageName:= 'ClIENTE'; with AttributesMapping do begin lAttribute:= Add; with lAttribute do begin AttributeName:= 'Id'; ColumnName:= 'OID'; IsOID:= True; IndexType:= idxUnique; Size:= 38; Required:= True; end;

lAttribute:= Add; with lAttribute do begin AttributeName:= 'LimiteDeCredito'; ColumnName:= 'LIMITEDECREDITO'; Required:= True; DataType:= adtCurrency; end; end; end;

No exemplo acima, com todo este código somente uma linha nos interessa:

InheritsMappingFrom:= TPessoa;

Esta linha identifica o relacionamento de generalização entre TCliente e TPessoa, somente isto énecessário para que quando criarmos um objeto TCliente e salvarmos o DePO guarde asinformações nos campos respectivos de cada tabela PESSOA e CLIENTE, e quando recuperarmosou excluirmos um objeto, o mesmo comportamente ocorrerá.Note que em ambos registros o valor do campo OID será identico pois do ponto de vista de objetosas informações pertencem a um único objeto do tipo TCliente.

Page 30: Delphi Persistent Object

DePO - Delphi Persistent Objects29

© <2004> http://www.liws.com.br/depo

Uma particularidade é que a propriedade ID deve ser mapeada novamente, caso contrario o DePOnão saberá como efetuar resolver este relacionamento, se a propriedade não for declaradanovamente, uma excessão será disparada, como o exemplo a seguir:

Propriedades de tipo objeto, com relacionamentos em classes superiores devem ser declaradasnovamente, senão o DePO não saberá desta relação. Por exemplo: A classe TPessoa possui apropriedade Emails: TEmails, na generalização de TCliente = class(TPessoa) a propriedade Emailsexistirá, mas TdpoDBMappingManager só sabera de um mapeamento entre TPessoa e TEmails,assim sendo só poderá retornar os emails de uma pessoa e nunca de um cliente.

O exemplo a seguir mostra como deve ser este relacionamento:

with MappingManager.Classes.Add do begin ClassObject:= TCliente; InheritsMappingFrom:= TPessoa; StorageName:= 'CLIENTE'; ...

with RelationshipsMapping.Add do begin RelatedClass:= TPessoa; MasterAttribute:= 'Emails'; IsRetrieveCascaded:= True; IsSaveCascaded:= True; IsDeleteCascaded:= True; Bindings.Add('Id=PessoaOID'); end; end;

O mapeamento deste relacionamento é idêntico ao mapeamento feito em TPessoa, mas essencialpara que as operações com Emails sejam transparentes.

Page 31: Delphi Persistent Object

IVDesenvolvendo Aplicações

Page 32: Delphi Persistent Object

DePO - Delphi Persistent Objects31

© <2004> http://www.liws.com.br/depo

4 Desenvolvendo Aplicações

4.1 Relacionamento entre os Objetos

Como implementar o relacionamento entre TCliente e TEnderecos e TEmails

Os passos necessários são:

1) Declarar as propriedades para as coleções e seus respectivos métodos GET.2) Declarar os campos responsáveis pelo relacionamento do tipo TdpoRelationshipResolver.3) Implementar os métodos GET.4) Mapear o relacionamento entre as classes5) Registrar as listas para o controle das coleções dos detalhes

1,2) A Interface da Classe:

TCliente = class(TdpoPersistentObject) private FEmails: TdpoRelationshipResolver; FEnderecos: TdpoRelationshipResolver;

... function GetEmails: TEmails; function GetEnderecos: TEnderecos; published property Emails: TEmails read GetEmails; property Enderecos: TEnderecos read GetEnderecos; end;

A implementação da criação dos relacionamentos

procedure TCliente.AfterConstruction;begin inherited; FEmails:= Relationships.Add('Emails'); FEnderecos:= Relationships.Add('Enderecos');end;

3) A Implementação dos métodos GET:

function TCliente.GetEmails: TEmails;begin if FEmails.RelatedObject = nil then begin FEmails.RelatedObject:= TEmails.Create(DBMechanism, Self, TEmail); FEmails.Retrieve; end; Result:= TEmails(FEmails.RelatedObject);end;

function TCliente.GetEnderecos: TEnderecos;begin

Page 33: Delphi Persistent Object

Desenvolvendo Aplicações 32

© <2004> http://www.liws.com.br/depo

if FEnderecos.RelatedObject = nil then begin FEnderecos.RelatedObject:= TEnderecos.Create(DBMechanism, Self,TEndereco); FEnderecos.Retrieve; end; Result:= TEnderecos(FEnderecos.RelatedObject);end;

4) A Implementação do mapenamento do relacionamento

with MappingManager.Classes.Add do begin ClassObject:= TCliente; StorageName:= 'CLIENTE'; with AttributesMapping do begin { O Mapeamento dos atributos será coberto em outro capítulo }

end; with RelationshipsMapping.Add do begin RelatedClass:= TEmail; MasterAttribute:= 'Emails'; IsRetrieveCascaded:= True; IsSaveCascaded:= True; IsDeleteCascaded:= True; Bindings.Add('Id=ClienteOID'); end;

with RelationshipsMapping.Add do begin RelatedClass:= TEndereco; MasterAttribute:= 'Enderecos'; IsRetrieveCascaded:= True; IsSaveCascaded:= True; IsDeleteCascaded:= True; Bindings.Add('Id=ClienteOID'); end; end;

A função RelationshipsMapping.Add adiciona um novo relacioanamento, por padrao em cadarelacionamento adicionado as seguintes propriedades são definidas como padrão:

function TdpoDBRelationshipMappingCollection.Add:TdpoDBRelationshipMapping;begin Result:= TdpoDBRelationshipMapping(inherited Add); with Result do begin Cardinality:= OneToMany; IsRetrieveCascaded:= False; IsSaveCascaded:= False; IsDeleteCascaded:= False;

Page 34: Delphi Persistent Object

DePO - Delphi Persistent Objects33

© <2004> http://www.liws.com.br/depo

end;end;

5) A Implementação do Registro das listas que controlam a coleção dos itens.

with MappingManager do begin RegisterList(TEmail, TEmails); RegisterList(TEndereco, TEnderecos); end;

4.2 (Re)Utilizando os Objetos

Reaproveitamento de objetos.

Para evitar ficar criando e destruindo sem critério, e também para não ficar executando instruçõesSQL desnecessárias, devemos definir como trabalhar com os objetos.

Trabalhar com coleções de objetos, definindo os critérios de retorno é um bom método, assimquando definido um critério e os objetos forem recuperados, podemos apenas navegar entre eles aiinvés de sempre efetuar novas consultas, isto também vale para os detalhes do objeto, ou seja,propriedades que são objetos, entao para uma classe TCliente que tem a propriedade do tipoTEnderecos, uma forma de otimizar o processo é que se os endereços ja forem recuperados, nãoprecisamos recuperar novamente.

Esta métodologia não é apropriada para casos em que os dados podem sofre alterações constantescom origem em outra localização, desta forma devemos ter uma forma de saber se os dados estãoatualizados, mas como saber sem retornar todos os dados novamente? e se retornarmos todos osdados novamente apenas precisamos atualizar a tela, mas isto gera um trafego de rededesnecessário se os dados já forem atualizados, e também a atualização de tela consumirá recursosdo computador. Então o problema começa a exigir uma análise mais detalhada de cada caso,algumas soluções são:

- Criar uma propriedade TimeStamp para ao invés de trafegar todos os campos, podemos compararatravés de um único campo, e a cada vez que o registro for atualizado, atualizaremos este campo.

- Outra forma é a atualização de um campo contendo o CRC do registro.

- Em caso de estações remotas, em que haja uma conexão de internet de baixa banda, podemosfazer o cache local com arquivos XML, trabalhando com DBExpress esta tarefa se torna muito fácil,e a cada vez que precisamos de um registro, apenas verificamos através do TimeStamp

- Outra forma seria apenas atualizar os dados antes de serem efetuadas operações no registro, ocorrespondente ao evento "OnBeforeEdit" do DataSet se encarregaria de chamar o método queatualizará os registros.

Nesto momento temos informações suficientes para perguntar "Como o Delphi trata isto com osDataSets?".- Vou usar como exemplo o DBExpress/ClientDataSet (Midas) para ter um comparativo. Toda vezque o evento OnAfterScroll é acionado, o Provider se encarrega de atualizar o registro atual,internamente o método UpdateRecord é chamado, fazendo com que o registro atual seja atualizado,este método garante que sempre os registros sejam sempre os mais atualizados possíveis, mas poroutro lado o trafego de rede aumenta consideravelmente, há também outros incovenientes que

Page 35: Delphi Persistent Object

Desenvolvendo Aplicações 34

© <2004> http://www.liws.com.br/depo

podem ocorrer dependendo do banco de dados utilizados, no caso do Interbase e do Firebird, se aaplicação estiver com uma transação ativa e o registro for alterado por outro usuário, mesmo que atransação do outro usuário esteja efetivada, enquanto a transação atual de quem estiver fazendoconsulta, não estiver finalizada, o banco dados se encarrega de ter estas informações guardadas,para que por exemplo não ocorra a seguinte situação, um usuário faz uma consulta e vê osresultados na tela (DBGrid ou Pré-Visualizando o Relatório), ai quando ele manda pra impressora,alguns minutos DePOis, quando o método scroll ocorre, o registro não seja atualizado, evitandoassim que o usuário não tenha um relatório impresso, diferente do que ele viu na tela.

Page 36: Delphi Persistent Object

VCriando Interfaces para Usuários

Page 37: Delphi Persistent Object

Criando Interfaces para Usuários 36

© <2004> http://www.liws.com.br/depo

5 Criando Interfaces para Usuários

5.1 Interfaces RAD

Com o componente TdpoDataSet você pode desenvolver interfaces como com qualquer outrodescendente de TDataSet.

Basta apenas defiinir as propriedades Mechanism e ObjectClassName, exemplo:

dpoDataSet1.Mechanism:= DBMechanism; dpoDataSet1.ObjectClassName:= 'TInvoice'; dpoDataSet1.Open;

As outras operações comuns a DataSet estão disponíveis: First, Previous, Nest, Last, Insert, Delete,Post, Cancel.

O método Post fará com que os dados digitados nos componentes DBware (TDBEdit, TDBGrid,etc...) sejam armazenados nos atributos dos objetos, para que os objetos sejam persistidos vocêdeve chamar o método ApplyChanges.

dpoDataSet1.Edit; dpoDataSet1.FieldByName('Date').AsDateTime:= Now; dpoDataSet1.ApplyChanges;

Outras características:

Se classe de lista do objeto estiver criada e registrada, o DePO a usará, caso contrário ele criaráuma lista genérica do tipo TdpoObjectList.

Em "Trabalhando com Objetos" - "Listas (Coleções)" aprenda como criar e manter listas.

É aconselhável que se crie as listas de objetos personalizadas para as classes, pois TdpoObjectListtratará os objetos contidos na lista de forma genérica, não conhecendo detalhes de suaimplementação, como propriedades que são classes.

Critério para recuperar os dados:

Antes de chamar o método open, você pode definir critérios para recuperar os dados: dpoDataSet1.Close; dpoDataSet1.Criteria.Add(ctEqualTo, 'Nome', ['Criando aplicações comDePO']); dpoDataSet1.Open;

24

Page 38: Delphi Persistent Object

VITécnicas Avançadas

Page 39: Delphi Persistent Object

Técnicas Avançadas 38

© <2004> http://www.liws.com.br/depo

6 Técnicas Avançadas

6.1 Tipos de dados

6.1.1 Imagem, Memo

Tipos de dados não comuns ou não suportados pelo banco de dados, precisam ser mapeadosatravés dos eventos OnGetValue e OnSetValue, DePO já traz suporte para alguns tipos de dados(Imagem, Strings, GUID e Boolean), mas você pode definir seus próprios métodos.

O tipo memo pode ser utilizado para trabalhar com TStringList como: RichText, StringStream,TStrings, etc.

Mapeamento Automático

Para trabalhar com tipos de dados Imagem e Memo, utilizando o mapeamento automático, defina apropriedade TdpoDBMappingManager.AutoConvertDataValues:= [acdvImage,acdvMemo], e:

Imagem:Defina a propriedade como TBitmap e no mapeamento, informe o DataType como adtImage

Memo:Defina a propriedade como TStrings e no mapeamento, informe o DataType como adtMemo

Exemplo:

TCliente = class(TdpoPersistentObject) private ... FFoto: TBitmap; FObservacao: TStrings; published ... property Foto: TBitmap read FFoto write FFoto; property Observacao: TStrings read FObservacao write FObservacao; end;

with MappingManager.Classes.Add do begin ClassObject:= TCliente; StorageName:= 'CLIENTE'; with AttributesMapping do begin with Add('Foto', 'FOTO') do DataType:= adtImage;

with Add('Observacao', 'OBSERVACAO') do DataType:= adtMemo; end; end;

Mapeamento manual

Page 40: Delphi Persistent Object

DePO - Delphi Persistent Objects39

© <2004> http://www.liws.com.br/depo

Um exemplo para Bitmap, por Cosimo de Michele

No mapeamento devemos especificar as os métodos GET e SET que serão chamados codificar edefinir e adquirir os valores dos dados em Stream (Sim, você pode usar estes métodos paracriptografar campos).

with AttributesMapping.Add dobegin AttributeName:= 'LogoPiccolo'; DataType:= adtImage; ColumnName:= 'LOGO16'; IndexType:= idxNone; IsOID:= False; OnGetValue:= TdpoAttributeGetSetValue.GetBitmap; OnSetValue:= TdpoAttributeGetSetValue.SetBitmap;end;

Agora devemos criar uma classe como esta:

TdpoAttributeGetSetValue = class class procedure GetBitmap(Attribute: TdpoAttributeMapping; AObject: TObject; var Value: Variant); class procedure SetBitmap(Attribute: TdpoAttributeMapping; AObject: TObject; Value: Variant); class procedure GetStringList(Attribute: TdpoAttributeMapping; AObject: TObject; var Value: Variant); class procedure SetStringList(Attribute: TdpoAttributeMapping; AObject: TObject; Value: Variant);end;

class procedure TdpoAttributeGetSetValue.GetBitmap( Attribute: TdpoAttributeMapping; AObject: TObject; var Value: Variant);var Buffer: TStringStream; Intro: TObjectIntrospector; BMP: TBitmap; V: Variant;begin Buffer:= TStringStream.Create(''); Intro:= TObjectIntrospector.Create(AObject); try V:= Intro.AttributeValue[Attribute.AttributeName]; TVarData(V).VType:= VarByRef; BMP:= TVarData(V).VPointer; BMP.SaveToStream(Buffer); if BMP.Empty then Value:= Null else Value:= Buffer.DataString; finally Buffer.Free; Intro.Free; end;end;

class procedure TdpoAttributeGetSetValue.GetStringList(

Page 41: Delphi Persistent Object

Técnicas Avançadas 40

© <2004> http://www.liws.com.br/depo

Attribute: TdpoAttributeMapping; AObject: TObject; var Value: Variant);var Buffer: TStringStream; Intro: TObjectIntrospector; lst: TStringList; V: Variant;begin Buffer:= TStringStream.Create(''); Intro:= TObjectIntrospector.Create(AObject); try V:= Intro.AttributeValue[Attribute.AttributeName]; TVarData(V).VType:= VarByRef; lst:= TVarData(V).VPointer; lst.SaveToStream(Buffer); if lst.Count = 0 then Value:= Null else Value:= Buffer.DataString; finally Buffer.Free; Intro.Free; end;end;

class procedure TdpoAttributeGetSetValue.SetBitmap( Attribute: TdpoAttributeMapping; AObject: TObject; Value: Variant);var Buffer: TStringStream; Intro: TObjectIntrospector; BMP: Graphics.TBitmap; V: Variant;begin Buffer:= TStringStream.Create(VarToStr(Value)); Intro:= TObjectIntrospector.Create(AObject); try Buffer.Position:= 0; V:= Intro.AttributeValue[Attribute.AttributeName]; TVarData(V).VType:= VarByRef; BMP:= TVarData(V).VPointer; BMP.LoadFromStream(Buffer); finally Buffer.Free; Intro.Free; end;end;

class procedure TdpoAttributeGetSetValue.SetStringList( Attribute: TdpoAttributeMadpping; AObject: TObject; Value: Variant);var Buffer: TStringStream; Intro: TObjectIntrospector; lst: TStringList; V: Variant;begin Buffer:= TStringStream.Create(VarToStr(Value)); Intro:= TObjectIntrospector.Create(AObject); try

Page 42: Delphi Persistent Object

DePO - Delphi Persistent Objects41

© <2004> http://www.liws.com.br/depo

Buffer.Position:= 0; V:= Intro.AttributeValue[Attribute.AttributeName]; TVarData(V).VType:= VarByRef; lst:= TVarData(V).VPointer; lst.LoadFromStream(Buffer); finally Buffer.Free; Intro.Free; end;end;

6.1.2 Boolean

Alguns bancos de dados não suportam o tipo Boolean, assim também podemos mapear este tipoatravés do mapeamento automático ou manual.

O suporte ao mapeamento automático para os tipos boolean está disponível da mesma forma que ostipos imagem, Strings e GUID, necessitando apenas que se defina o DataType como adtBoolean.

Exemplo:

TCliente = class(TdpoPersistentObject) private ... FPreferencial: Boolean; published ... property Preferencial: Boolean read FPreferencial write FPreferencial; end;

with MappingManager.Classes.Add do begin ClassObject:= TCliente; StorageName:= 'CLIENTE'; with AttributesMapping do begin with Add('Preferencial', 'PREFERENCIAL') do DataType:= adtBoolean; end; end;

O mapeamento automático depende de que a propriedade AutoConvertDataValue do componenteTdpoDbMappingManager tenha acdvBoolean ou acdvBooleanAsInteger (exclusivos), seacdvBooleanAsInteger estiver definido como True, a propriedade ColumnTypeForBoolean deve ter ovalor Integer ou outro tipo numérico suportado pelo Banco de Dados e os valores salvos serão 0 paraFalso e 1 para Verdadeiro, caso contrário, ColumnTypeForBoolean deverá ser CHAR(1), ou outrosemelhante, e os valores serão T para verdadeiro e F para Falso.

Se for necessário os eventos OnGetValue e OnSetValue podem ser utilizados para personalizarcampos boolean, basta apenas definir os métodos no mapeamento e implementá-los:

with MappingManager.Classes.Add do begin

Page 43: Delphi Persistent Object

Técnicas Avançadas 42

© <2004> http://www.liws.com.br/depo

ClassObject:= TCliente; StorageName:= 'CLIENTE'; with AttributesMapping do begin with Add('Preferencial', 'PREFERENCIAL') do begin DataType:= adtBoolean; OnGetValue:= TCustomMaps.GetBoolean; // Class Function OnSetValue:= TCustomMaps.SetBoolean; // Class Procedure end; end; end;

6.1.3 TDateTime

Para Firebird e Interbase, quando mapear as classes, os campos do tipo TDateTime devem ser pré-definidos como adtTimeStamp:

with MappingManager.Classes.Add do begin ClassObject:= TPerson; StorageName:= 'PERSON_TABLE'; with AttributesMapping do begin lAttribute:= Add; with lAttribute do begin AttributeName:= 'Nascimento'; ColumnName:= 'DT_NASCIMENTO'; DataType:= adtTimeStamp; end; end; end;

Se estiver trabalhando com componentes dbware, antes de passar os valores para os TFields, testese a propriedade não está com valor igual a zero, pois quando um TField recebe uma data de valorzero ele atribui a primeira data válida, utilizada pelo Delphi "30/12/1899"

if lCliente.DataNascimento <> 0 then cdsClientes.FieldByName('DataNascimento').AsDateTime:=lCliente.DataNascimento;

if lCliente.QualquerHora <> 0 then cdsClientes.FieldByName('QualquerHora').AsDateTime:=lCliente.QualquerHora;

6.2 Clonando Objetos

A classe TdpoPersistentObject implementa o método AssignTo como protected, desta forma todasas classes derivadas de TdpoPersistentObject poderão ser clonados.

Exemplo:

var

Page 44: Delphi Persistent Object

DePO - Delphi Persistent Objects43

© <2004> http://www.liws.com.br/depo

Person: TPerson; ClonedPerson: TPerson;

Person:= TPerson.Create(DBMechanism); ClonedPerson:= TPerson.Create(DBMechanism); { definindo as propriedades de Person } Person.Name:= 'Cesar Romero'; Person.Email.Add('[email protected]'); Person.Email.Add('[email protected]');

{ Clonado Person para ClonedPerson } Person.AssignTo(ClonedPerson);

Criei um gêmeo meu :)

Isto mesmo, é como se criasemos um gêmeo, pois quando você executa o seguinte método:ClonedPerson:= Person;ClonedPerson armazena um ponteiro para Person, ou seja Person e ClonedPerson são o mesmoobjeto, se você destruir um, o outro também será excluído, pois são o mesmo.

Mas com AssignTo, você faz uma cópia idêntica, mas se uma for destruída a outra continuaráintacta.

6.3 Utilizando Proxy

De acordo com Scotty Ambler, Proxy é um objeto que identifica outro, mas sem a sobrecarga que orepresentado tem, ou seja, em todas as propriedades. Um proxy deve conter informações suficientespara que ambos, o computador e o usuário possa identificá-lo e nada mais. Por exemplo o proxypara uma pessoa deve conter seu OID para que a aplicação possa identifica-lo e Nome e Iniciaispara representa-lo e o usuário poder identificálo. Proxys são comuns em listas de objetos para que ousuário possa selecionar somente os desejados, após a seleção somente o objeto selecionado serárecuperado completo. Utilizando proxy você pode reduzir a carga de informações que irão trafegarna rede.

Ao invés de representar o proxy por outro objeto, DePO implementa Proxy como uma lista decampos que você deseja, esta lista é a propriedade ProxyAttribute: TStringList da IdpoQuery, paraincluir os campos. Esta implementação torna fácil a programação, dispensando a necessidade de secriar outra classe para ser proxy, de uma forma simples economizamos trafego de rede, por outrolado os objetos estão carregados na memória completos, mas sem valores nas propriedades.

Exemplo:

type TClientes = class(TdpoPersistentObjectList) private function GetItem(const Index: Integer): TCliente; reintroduce; public property Items[const Index: Integer]: TCliente read GetItem; default; function Add: TCliente; reintroduce; function New: TObject; reintroduce; end;

TCliente = class(TdpoPersistentObject) published property ID: String read FID write SetID;

Page 45: Delphi Persistent Object

Técnicas Avançadas 44

© <2004> http://www.liws.com.br/depo

property Nome: String read FNome write SetNome; property UltimoNome: String read FUltimoNome write FUltimoNome; property Iniciais: String read FIniciais write FIniciais; property Telefone: String read FTelefone write FTelefone; property Foto: TBitmap read GetFoto write SetFoto; property Observacao: TStrings read GetObservacao write SetObservacao; end;

var DBMechanism: TdpoCustomMechanism; Clientes: TClientes; lCliente: TCliente;

lCliente:= TCliente.Create(DBMechanism); Clientes:= TClientes.Create(DBMechanism, TCliente); Clientes.Query.ProxyAttribute.Add('ID'); Clientes.Query.ProxyAttribute.Add('Nome'); Clientes.Populate;

No exemplo acima utilizamos a propriedade Query para definir o proxy.Outra forma de utilizar Proxy é definindo diretamento quando executamos a query noTdpoCustomMechanism, como no exemplo a seguir:

with DBMechanism.CreateQuery(TCliente) do begin ProxyAttribute.Add('ID'); ProxyAttribute.Add('Nome'); Open; end;

6.4 Critérios para recuperar Objetos

Recuperar Objetos por Critérios, Básico, por Paulo Roberto Quicoli

O DePO oferece critérios para seleção de objetos que operam como os comparadores SQL ( AND,LIKE, >=, ISNULL, etc).A lista abaixo mostra os critérios para se comparar um campo a um valor:

· ctEqualTo· ctLike· ctGreaterOrEqualThan· ctGreaterThan· ctLessOrEqualThan· ctLessThan· ctBetween· ctIn· ctIsNull· ctCustom

Utilizando os Critérios

Nada explica melhor do que um pequeno exemplo comentado. Segue abaixo:

FContatoList:= TContatos.Create(DBMechanism, TContato); FContatoList.Criteria.Add(ctIsNull, 'ID', [Null], True);

Page 46: Delphi Persistent Object

DePO - Delphi Persistent Objects45

© <2004> http://www.liws.com.br/depo

FContatoList.Populate;

1ª linha : Criamos nossa lista de objetos, que contém objetos do tipo TContato;2ª linha : Através do método Criteria.Add incluimos um criterio para busca. no exemplo acimaestamos recuperando os objetos que possuam o atributo 'ID' nulo. O SQL gerado pelo criteria é algoassim:

SELECT ... FROM CONTATO WHERE NOT (ID IS NULL)

3ª linha : Recuperamos os objetos.

Veja a assinatura da função

function Add(ACriterionType: TdpoCriterionType; AAttribute: String; const AValue: array of Variant; AIsNOT: Boolean = False): TdpoCriterion;overload;

Parâmetros:

ACriterionType - É um dos critérios mencionados acima AAttribute - Nome do atributo da tabela AValue - Array de valores a serem comparados AIsNOT - Se for TRUE, acrescenta negação à comparação. Vide exemplo acima.

Combinando Critérios

Através do método Add, você pode adicionar mais de um critério para recuperação dos objetos. Todocritério de seleção adicionado pelo método Add, irá gerar uma cláusula AND ao WHERE.Veja exemplo:

Root:= TCategories.Create(dpoADOMechanism1, TCategory); Root.Criteria.Add(ctIsNull, 'FatherOID', [Null], True); Root.Criteria.Add(ctLike, 'DESCRIPTION',['Ce']); Root.Populate;

Através dessa configuração é gerado o seguinte SQL :

SELECT CATEGORY.ID, CATEGORY.DESCRIPTION, CATEGORY.ID_FATHER FROM CATEGORY WHERE NOT(CATEGORY.ID_FATHER IS NULL) AND CATEGORY.DESCRIPTION LIKE:P0

Obs.:O valor 'Ce' será passado para a sentença através do parâmetro :P0

Para adicionar uma cláusula OR, temos o método AddOR, conforme demonstrado abaixo:

Root:= TCategories.Create(dpoADOMechanism1, TCategory); Root.Criteria.Add(ctIsNull, 'FatherOID', [Null], True); Root.Criteria.AddOr(ctLike, 'DESCRIPTION',['Ce']); Root.Populate;

Que resulta na seguinte sentença SQL:

SELECT CATEGORY.ID, CATEGORY.DESCRIPTION, CATEGORY.ID_FATHER FROM CATEGORY WHERE NOT(CATEGORY.ID_FATHER IS NULL) OR CATEGORY.DESCRIPTION LIKE:P0

Obs.:O valor 'Ce' será passado para a sentença através do parâmetro :P0

Page 47: Delphi Persistent Object

Técnicas Avançadas 46

© <2004> http://www.liws.com.br/depo

6.5 Ordem de recuperação (Sort)

Ordenação de Resultados, por Paulo Roberto Quicoli

Pode-se também ordernar os objetos retornados. O DePO disponibiliza o método OrderBy.Add pararealização de ordernações. Veja o exemplo:

Root:= TCategories.Create(dpoADOMechanism1, TCategory); Root.Criteria.Add(ctIsNull, 'FatherOID', [Null], True); Root.Criteria.AddOr(ctLike, 'DESCRIPTION',['Ce']); Root.OrderBy.Add('DESCRIPTION'); Root.Populate;

Através dessa combinação será gerada a seguinte senteça SQL:

SELECT CATEGORY.ID, CATEGORY.DESCRIPTION, CATEGORY.ID_FATHER FROM CATEGORYWHERE NOT(CATEGORY.ID_FATHER IS NULL) OR CATEGORY.DESCRIPTION LIKE:P0ORDER BY CATEGORY.DESCRIPTION ASC

Veja a assinatura do método OrderBy.Add:

function Add(AAttribute: String; ADescending: Boolean = False):

Parâmetros:AAttribute: Atributo da tabela que será utilizado para ordenação;ADescending: Indica se a ordenação será Ascendente ou Descendente, sendo padrão Ascendente;

Combinando ordenações

Podemos também combinar ordenações. Veja o exemplo:

Root:= TCategories.Create(dpoADOMechanism1, TCategory); Root.Criteria.Add(ctIsNull, 'FatherOID', [Null], True); Root.Criteria.AddOr(ctLike, 'DESCRIPTION',['Ce']); Root.OrderBy.Add('DESCRIPTION', True); Root.OrderBy.Add('FatherOID'); Root.Populate;

Resultará na seguinte sentença SQL:

SELECT CATEGORY.ID, CATEGORY.DESCRIPTION, CATEGORY.ID_FATHER FROM CATEGORYWHERE NOT(CATEGORY.ID_FATHER IS NULL) OR CATEGORY.DESCRIPTION LIKE:P0ORDER BY CATEGORY.DESCRIPTION DESC, CATEGORY.ID_FATHER ASC

6.6 Transações

Transações no DePO são tratadas de forma transparente, se nenhuma for definida manualmente, oDePO se encarregara de criar uma, se o mecânismo de persistência suportar.

Se um objeto possui relacionamentos, definidor por propriedades do tipo TdpoRelationshipResolver,e este relacionamento estiver com a propriedade "IsSaveCascaded = True", todos os objetosrelacionados serão salvos na mesma transação.

Page 48: Delphi Persistent Object

DePO - Delphi Persistent Objects47

© <2004> http://www.liws.com.br/depo

Se uma transação for definida manualmente antes de chamar o método save, DePO não criará outratransação enquanto esta transação não for finalizada através de Commit ou Rollback.

Exemplo

procedure TfrmMenu.sbtPopulateClick(Sender: TObject);var I, J: Integer; lFather: TPerson; lChield: TPerson; lTransaction: TTransactionDesc; ID: Integer;begin { Defining own transaction } ID:= 0; lTransaction.TransactionID:= ID + 1; lTransaction.IsolationLevel:= xilREADCOMMITTED; DB.StartTransaction(lTransaction); try for I:= 1 to 10 do begin lFather:= lotPeople.Add; { OID as Sequence, will raise if Populate more than once } lFather.ID:= IntToStr(I); lFather.Name:= Format('Father %d', [I]); for J:= 1 to 15 do begin lChield:= lFather.Chields.Add; lChield.ID:= Format('%d.%d', [I, J]); lChield.Name:= Format('Chield %d.%d', [I, J]); lChield.FatherOID:= lFather.ID; end; { Save Father and all Chields } lFather.Save; end; DB.Commit(lTransaction); except DB.Rollback(lTransaction); end;end;

Page 49: Delphi Persistent Object

VIIExtras

Page 50: Delphi Persistent Object

DePO - Delphi Persistent Objects49

© <2004> http://www.liws.com.br/depo

7 Extras

7.1 ModelMaker

Para utilizar os componentes do DePO com o ModelMaker basta importar a unitdpoPersistanceObject e os objetos base estarão disponíveis para serem generalizados etransformados em Objetos de Negócio.

Para importar uma unit basta clicar com o botão direito na "View Unit (F4)" e selecionar "Importunit..."

No diálogo "Select aliased Path..." clique em "<No alias>"

Selecione o arquivo "dpoPersistanceObject.pas"

Page 51: Delphi Persistent Object

Extras 50

© <2004> http://www.liws.com.br/depo

Para não criar vínculo com o arquivo da unit, evitando que alterações no modelo afetem a unit noDePO, clique no Botão "Interfaces", desta forma o ModelMaker selecionará Membros e Opções deimportação, para ter o código dos métodos disponíveis no ModelMaker, marque a opção "IncludeMethod Implementation".

Clique no botão "Abrir" e o diálogo "Import classes" trará a lista de todas as interfaces, classes,registros e eventos disponíveis na unit, selecione as classes TdpoPersistentObject eTdpoPersistentObjectList.

Page 52: Delphi Persistent Object

DePO - Delphi Persistent Objects51

© <2004> http://www.liws.com.br/depo

Clique em OK e as classes estarão disponíveis para utilizar no ModelMaker na View Classes

Desta forma quando for adicionar uma nova classe, basta selecionar o Ancestor desejado,TdpoPersistentObject ou TdpoPersistentObjectList:

Page 53: Delphi Persistent Object

Extras 52

© <2004> http://www.liws.com.br/depo

Para definir o relacionamento "TItems.Items[Index] -TInvoiceItem" no diálogo Property Association,defina:· ReadAccess como Method· WriteAccess como None· Marque "array property",e· Marque "Default array property"

Page 54: Delphi Persistent Object

DePO - Delphi Persistent Objects53

© <2004> http://www.liws.com.br/depo

Page 55: Delphi Persistent Object

VIIIHistória

Page 56: Delphi Persistent Object

DePO - Delphi Persistent Objects55

© <2004> http://www.liws.com.br/depo

8 História

08/08/2004- DePO

· (Novo) TdpoDataSet

· Corrigido bugs de operações em cascata

- DePO Manual· Arquitetura - Mapeamento de Objetos - De Objetos para RDB, por Marcos Barreto· Trabalhando com Objetos - Listas Coleções, atualizado· Trabalhando com Objetos - Problemas com Operações em Cascata· Criando Interfaces para usuários - Interfaces RAD (TdpoDataSet)· Extras - ModelMaker· Novo Logotipo, por Marcos Barreto· 58 páginas

29/07/2004- DePO

· (Novo) Implementado InternalConnection para DBXMechanism e ADOMechanism, umaconexão interna chamada InternalConnection será criada, mas uma personalizada poderá serselecionada, neste caso a InternalConnection será destruída.

· A propriedade DBXConnection do DBXMechanism foi eliminada e Connection sobrescrita comoTSQLConnectionAtenção: Quando abrir os Forms que contém o componente TdpoDBXMechanism, Delphimostrará uma mensagem de erro, dizendo que a propriedade DBXConnection não existe,pressione OK para continuar, se em seu código você estiver usando esta propriedade substituapor Connection.

Sugestão de Marcos e Paulo· (Novo) Ícones para componentes DePO: TdpoDBMappingManager, TdpoDBXMechanism e

TdpoADOMechanism

· (Novo) Criada a propriedade TdpoDBMappingManager.AutoConvertDataValues = (acdvImage,acdvMemo, acdvGUID, acdvBooleanAsInteger), para mapeamento automático de tipos de dadosnão suportados pelo banco de dados, como Imagem, Strings e Boolean no Firebird e Interbase.Estas alterações dispensam a necessidade que havia de se criar os Get's e Set's para estes tiposde dados. Sugestão de Marcos

Page 57: Delphi Persistent Object

História 56

© <2004> http://www.liws.com.br/depo

· Critério: Between e IN por Paulo R. Quicoli em 26/07/2004· Corrigido problemas com exclusão em cascata no método TdpoCustomMechanism.DeleteList,

sugestão de AledeOl

- DePO Manual· Técnicas Avançadas - Tipos de dados - Imagem, Memo· Técnicas Avançadas - Tipos de dados - Boolean· 45 páginas

- Exemplos· (Novo) Exemplo Enumeration: mostra como utilizar tipo enumerados: TRealizacao = (reDiario,

reDomingo, reSegunda, reTerca, reQuarta, reQuinta, reSexta, reSabado);· Many, atualizado para utilizar TdpoDBMappingManager.AutoConvertDataValues para Boolean,

Imagem e Memo.

22/07/2004- DePO

· TdpoDBClassMapping, criada as propriedades ClassObjectName e InheritsMappingFromNamepara mapeamento diretamente na IDE do delphi no Object Inspector.

· dpoClassMapping, dpoPersistanceObject, implementada operações em cascata paraGeneralização (herança).

- DePO Manual· Arquitetura - Declarando Objetos (não finalizado)· Arquitetura - Mapeando Objetos· Arquitetura - Sincronizando o banco de dados· Trabalhando com Objetos - Operações em Cascata· Trabalhando com Objetos - Generalização· 40 páginas

- Exemplo Cascate· Herança, exemplo de derivar uma classe e o DePO salvar automaticamente a classes de que é

derivada.

21/04/2004- DePO

Page 58: Delphi Persistent Object

DePO - Delphi Persistent Objects57

© <2004> http://www.liws.com.br/depo

· dpoDatabaseMechanism.TdpoSQLSelectStatement function TdpoSQLSelectStatement.GetSQLSelectFrom: String; Quando havia ProxyAttribute na query, o nome da tabela se repetia N vezes campos, gerandoFROM errado no SQL

· dpoPersistanceObject.TdpoObjectList Incluída a propriedade Query como pública, se para poder utilizar Proxy comTdpoPersistentObjectList.· dpoDBXMechanism TdpoDBXCommand.SetParamList e TdpoDBXQuery.SetParamList Eliminado código desnecessário para definir parâmetros.

- Exemplo DBWare· Incluído proxy na busca dos registros· Definido o DataType dos campos dos tipos TDateTime, TImage/TBitmap e TSream no

mapeamento das classes.

- DePO Manual· Arquitetura - Classes e Propriedades· Trabalhando com Objetos - Herança· Técnicas Avançadas - Critérios para recuperar, por Paulo Roberto Quicoli· Técnicas Avançadas - Ordem de recuperação, por Paulo Roberto Quicoli· Técnicas Avançadas - Utilizando Proxy· Técnicas Avançadas - Clonando Objetos· Técnicas Avançadas - Tipos de dados - "Imagem, RTF, Stream", Boolean e TDateTime· Atualizado "Todo List" e "Problemas conhecidos", itens implementados foram eliminados

20/04/2004- Criado um novo exemplo Cascate.dpr:

· Salvar em cascata· Excluir em cascata· Gerenciar Transações em DBExpress manualmente· Utilizar OID de origens diferentes na mesma tabela· Objeto pai· Popular TListBox com Objetos

- DePO Manual· Técnicas Avançadas - Transações· Técnicas Avançadas - Campos Blob (Imagem, RTF), por Cosimo de Michele· Trabalhando com Objetos - OID

19/04/2004- Correções nos parâmetros da TDBXCommand e TDBXDataSet para trabalhar com camposTDateTime, Boolean e Blob, testado com firebird- Implementado Transações no DBXMechanism