Tutorial ParallaxDB - versão 2.0





Informações
- 100% JDBC.
- Não utiliza nenhuma biblioteca externa, somente o que vem no JDK.
- Dentro dos Padrões da JPA.
- Funciona tanto no SO Android (Somente o SQLite foi testado no Android) como em computadores domesticos e empresariais (Todos os bancos informados aqui) que tenham a JDK instalado.
- Pré-Requisito: Java 6+.
- Suporta os seguintes bancos de dados: MySQL, SQLite, Firebird 1.5+, Apache Derby, PostGreeSQL.
- É obrigatorio ter na lib o driver JDBC de um dos bancos de dados disponiveis acima!
- O framework só trabalha com chave primaria simples (Ele não trabalha com chave primaria composta).
- Versão atual 2.0
Instalando
1°) Baixe o arquivo parallaxdb.jar
2°) copie para sua pasta lib e adicione o parallaxdb.jar ao seu projeto.
3°) Baixe o driver jdbc do seu banco de dados, ponha também na pasta lib e adiciona o jar do driver jdbc no projeto.
4°) Adicione o arquivo parallax.properties ao projeto (Veja mais na seção "Preparando o Ambiente").
Obs.: Existe o projeto ParallaxDBSecurityProperties, este projeto tem a função de criar o properties acima aplicando criptografia na senha, isso garante que não vão saber a senha do seu banco de dados.
== ATENÇÃO ==
Se for usar o Android: adicione o SQLDroid dentro da pasta libs do projeto Android (Arquivos: sqldroid-1.0.0RC1.jar e sqldroidsecompat-1.0.0RC1.jar) e não coloque o driver jdbc do SQLite (O SQLDroid subistitui o driver jdbc padrão, sendo feito exclusivamente para Android) e no arquivo parallax.properties ponha o valor do "type.database=sqldroid".
== Agora é só utilizar ==
Como utilizar
Vídeo (Ver. 1.0 - Depreciated): [Parallax 3.0] ParallaxDB - Framework de persistencia Android.& Desktop
Vídeo (ver. 1.5 - Depreciated): [ParallaxDB - Ver. 1.5] - Framework de persisntecia - Tutorial Android e Desktop
Vídeo (ver. 2.0): [ParallaxDB - Ver. 2.0] - Framework de persistecia - Tutorial Android e Desktop
Apresentação (SlideShare 1.0/1.5 - Depreciated): ParallaDB - Framework de Persistência Android e Desktop
Apresentação (SlideShare 2.0):
Criando o DTO (Data Transfer Object)
Resumo DTO: É uma classe que representa uma tabela do banco de dados, assim como seus atributos representam as colunas da tabela.
Anotações:
- @Entity(name="NomeDaTabela") - Informa a qual tabela a classe esta vinculada.
- @Id - Informa qual campo é a chave primaria.
- @GeneratedValue - Informa que o auto incremento é gerado pelo banco de dado.
- @Column(name="cliente_codigo") - Informa o nome da coluna no banco de dado ao qual o atributo faz referencia.
- @Transient - Informa que o atributo não é persistente no banco de dados.
- @Active - Informa que o campo é quem vai ter a informação de Ativo/Inativo (Registro logicamente excluido e não fisicamente).
- @ManyToOne(joinColumn="NomeDaChaveEstrangeira") - Informa qual é o atributo que contem a chave estrangeira e popula o mesmo.
- @OneToMany(fkField="NomeDaChaveEstrangeiraNaTabelaEscrava", targetEntity="NomeDaClasseDTOEscravo.class") - Informa que o atributo contem a lista de detalhes(escravo) dessa tabela Mestre e popula o mesmo.
Observações:
1. Nas colunas "name" quando não informado o nome da coluna na tabela, o framework considera que é o mesmo nome do atributo, ligado a anotação.
2. Mesmo sem o arroba Column o framework entende que todos os atributos são persistentes, exceto os marcados como @Transient, porém é interessante usar o @Column quando o nome do campo e do atributo é diferente ou por fim de organização.
Criando meu DTO:
@Entity(name="TabelaCliente")
public class Cliente {
@Id
private int codigo;
@Active
private int ativo;
@Column
private String nome;
@Transient
private String esteatributoNaoPersisteNoBancoDeDados;
@ManyToOne(joinColumn="Cidade_Id")
private Cidade cidade;
@OneToMany(fkField="Clienete_Id", targetEntity=Dependente.class)
private List
}
Boas praticas com DTO (Data Transfer Object)
Uma boa pratica no DTO é sobreescrever os metodos hasCode(), equals() e toString(), isso influencia em situações de comparação e ordenamento quando utilizamos o DTO em uma lista. Abaixo alguns modelos:
/**
* Metodo para a comparação entre dois objetos
*
* @param obj - Objeto para a comparação
* @return boolean - True=Objetos iguais | false=Objetos diferentes
*
*/
@Override
public boolean equals(Object obj) {
if ( this == obj ){
return true;
} else if ( this == null ){
return false;
} else if ( !(obj.getClass() == this.getClass()) ){
return false;
} else if ( ((BaseDTO)obj).getId() == this.getId()){
return true;
}
return false;
}
/**
* Metodo que ordena através de código hash
*
* @return int - Código hash
*/
@Override
public int hashCode() {
int hash = 1;
hash = hash * 31 + this.getId();
return hash;
}
/**
* Metodo que retorna um texto, quando chamam o objeto
* diretamente "new objeto()" ou "new objeto().toString()"
*
* @return String - Texto personalizado
*/
@Override
public String toString() {
return "id: " + this.getId();
}
Utilizando o DAO (Data Acess Object)
Não existe a necessidade de se criar um DAO, basta usar a chamada "DAO.getInstance().<NomeDoMetodo>", ai vem a pergunta, como o DAO sabe a qual DTO ele faz referencia, para manipular? Todos os metodos do DAO pedem o "class" do DTO como parmetro.
Exemplo: DAO.getInstance().getList(Cliente.class); //Esta retornando todos os cliente do banco de dados
3°) Quais são os metodos importantes do DAO?
Primeiro lembre-se de ler o JavaDoc do projeto, todas as classes e metodos estão documentadas. Abaixo apenas um resumo dos metodos uteis pertencentes ao framework.
- get(Class, int): Retorna um registro baseado na chave primaria.
- getList(Class): Retorna todos os registros.
- getBy(Class clazz, String): Retorna N registros baseados em uma condicional (Ex.: "codigo=1 and nome like '%teste%'")
- countRecords(Class clazz): Retorna o total de registros.
- save(Object): Insere ou atualiza o registro no banco de dados
- insert(Object): Insere o registro no banco de dados
- update(Object): Atualiza o registro no banco de dados
- delete(Object): Deleta o registro do banco de dados
- getPagination(Class): Retorna o objeto de paginação com os seus metodos de manipulação de um DTO especifico, por exemplo paginei a tabela Mestre e Detalhe, quero manipular a paginação do Detalhe, passo no argumento do metodo "Detalhe.class", caso queira paginar o Mestre utilizo o "Mestre.class" no argumento do metodo. veja mais em "Paginação dos Dados".
- isUsingPagination(Class): TRUE = esta utilizando a paginação no retorno dos dados, FALSE = Não esta usando.
- setUsingPagination(Class, boolean): Passa o Class do DTO e informa se o mesmo deve ou não utilizar a paginação.
- isBringInactiveRecords(Class): TRUE = Retorna até os registros inativos do DTO especificado no class, FALSE = Não retorna registros que estejam marcados como inativos.
- setBringInactiveRecords(Class, boolean): Aqui é onde informamos se deve ou não trazer registros inativos do DTO informado no "Class" (Por exemplo é usado o @Active no DTO, porém por algum motivo queremos trazer até os inativos, neste caso marcamos como true este metodo antes de uma consulta e toda consulta após ele feita neste DTO retornara os inativos).
- getOrderBy(SqlOrderBy, String...): Retorna a String SQL da instrução "Order By " (SqlOrderBy é um Enum).
- set/getConnection(): Altera ou Recupera a conexão corrente.
Observação: todos os que estão sublinhados são afetados pela paginação.
Paginação dos Dados
Quando trabalhamos com tabelas ou listas é comum querer pagina-las em algum momento. Porém o algoritomo para fazer isso costuma ser custoso, trabalhoso, dificil e ainda varia de base de dados para base de dados. Para resolver isso já foi implementado a paginação no proprio Framework. Abaixo alguns metodos de apoio.
1°) Movendo entre paginas.
- goFirstPage(): Vai para a primeira pagina
- goNextPage(): Vai para a proxima pagina
- goPreviousPage(): Vai para a pagina anterior
- goLastPage(): Vai para a ultima pagina
- goSelectedPage(int):Informa o numero da pagin que deseja ir.
2°) Habilitando e desabilitando botões
- set/is StateButtonLast(...): É atualizado automaticamente e pode ser usado para habilitar/desabilitar um componente (Ex.: Botão ">").
- set/is StateButtonFirst(...): É atualizado automaticamente e pode ser usado para habilitar/desabilitar um componente (Ex.: Botão "<").
- set/is StateButtonNext(...): É atualizado automaticamente e pode ser usado para habilitar/desabilitar um componente (Ex.: Botão ">>").
- set/is StateButtonPrevious(...): É atualizado automaticamente e pode ser usado para habilitar/desabilitar um componente (Ex.: Botão "<<").
3°) Informativo
- getCurrentPage(): Pagina atual
- getQuantityPages(): Quantidade de paginas
- set/get QuantityRecords(): Quantidade total de registros
- PAGE_SIZE: Numero de registros por pagina
Preparando o Ambiente
1°) Antes de tudo informe no projeto principal o local onde se localiza o parallax.properties, abaixo um exemplo utilizando a LibGDX:
String filePath = Gdx.files.getLocalStoragePath() + "parallax.db";
InputStream fileProperties = Gdx.files.internal("data/parallax.properties").read();
Util.getInstance().loadGlobalProperties(fileProperties, filePath);
Onde "fileProperties" é onde localiza-se o arquivo properties, no exemplo acima ele esta em "assets/data/parallax.properties" (Seguindo o padrão da LibGDX). O "filePath" indica o local onde se localiza o banco de dados (Lembrando que este parametro é opcional, pois pode ser indicado no properties também, porém prevalece o valor indicado no properties caso ambos existam).
2°) Entendendo os parametros do parallax.properties.
- type.database (Obrigatorio): Indica qual banco de dados vai ser usado, abaixo os valores validos para o mesmo:
- derby, sqlite, mysql, firebird, postgresql (Apenas para aplicações Desktop)
- sqldroid (Apenas para aplicações Android, indica acesso ao banco de dados SQLite)
Atenção: Ao informar este atributo ele automaticamente carrega a url, urlPrefix e o classForName padrões para o tipo especificado.
- pagination.pagesize (Obrigatorio): Informa qual o numero de registros a serem exibidos por pagina.
Ex.: pagination.pagesize=5
- connection.classForName (Opcional): Informa o driver jdbc a ser usado.
Ex.: connection.classForName=org.sqlite.JDBC
- connection.urlPrefix (Opcional): Informa o prefixo da URL.
Ex.: connection.urlPrefix=jdbc:sqlite:
- connection.url (Opcional): Informa a url do banco de dados (Seu caminho completo)
Ex.: connection.url=c:\\Teste\\banco.db
- connection.user (Opcional): Informa o login de acesso do banco de dados.
Ex.: connection.user=parallax
- connection.password (Opcional): Informa a senha de acesso do banco de dados.
Ex.: connection.password=parallax123
- connection.password.crypt (Opcional): Informa se a senha informada no properties e criptografada, se for TRUE ele vai descriptografar a senha antes de checar a base de dados (Veja o modelo de criptografia aplicada no ConnectionFactory do projeto ParallaxDB).
Ex.: connection.password.crypt=false


Comentários
As mudanças foram muito bruscas internamente, mas o resultado no sentido performance e facilidade ficaram muito mais efetivas, a mudança de paradigma onde atráves de um cache de DAO fazia as ações agora tenho um cache dos DTOs.
Dois metodos talvez sejam trazidos de volta
getListByValue( ...) e o getUniqueObject ByValue(...), estou refletindo sobre eles.
Assine o RSS dos comentários