quinta-feira, 25 de outubro de 2012

Android: Acessando banco de dados fácil e rápido com ORM ! (Avançado)

















Olá amigos, vamos a mais um artigo sobre como trabalhar com Android e banco de dados.
Caso você não tenha lido a primeira parte, sobre como criar a camada de acesso a dados, aí vai o link http://strangerdroid.blogspot.com.br/2012/10/android-acessando-banco-de-dados-facil.html.
Nessa segunda postagem, vamos falar sobre conceitos mais avançados a respeito da ferramenta ORMLite.
Se você fez o exemplo do primeiro artigo, imagino que você tenha se perguntado: "OK, mas como uso uma clausula 'where', 'order' ou 'join'?".
Sem dúvida, essa é uma pergunta muito pertinente !
Na maioria das ferramentas ORM é possível executar todos esses comandos sem escrever nenhuma linha de código sql, no ORMLite não é diferente.
Para exemplificar, usaremos o projeto do artigo anterior, ok?
Vamos fazer mais exemplos?

Passo 1. Usando WHERE para filtrar suas consultas

Abra o arquivo ClientesDAO no package dao. (no meu caso está no package br.com.exemplo.db.dao)
Vamos escrever um método que filtre os resultados apenas dos clientes com sobrenome iguais a "Silva".
Faça a implementação como no exemplo.



public List<Clientes> getBySobreNomeSilva() {
List<Clientes> clientes = new ArrayList<Clientes>();

try{
QueryBuilder<Clientes, Integer> queryBuilder = dao.queryBuilder();
queryBuilder.where().eq("sobrenome", "Silva");
clientes = dao.query(queryBuilder.prepare());
}catch(Exception e){
e.printStackTrace();
}

return clientes;
}

Nesse método retornamos uma lista de Clientes.
Criamos um objeto do tipo QueryBuilder onde trabalharemos com o tipo Clientes e a PK dele é do tipo integer.
Este objeto é responsável pela clausula 'where sobrenome seja igual (eq) "Silva"'.
O último passo é enviar essas informações para a classe dao do ORMLite processar a query.
Simples, não é? Nenhuma linha SQL. :) Próximoooooo.....


Passo 2. Ordenando a sua consulta

No próximo exemplo vamos ordenar o resultado da nossa consulta trazendo todos os registros de clientes ordenando pelo primeiro nome.


public List<Clientes> getByNome() {
List<Clientes> clientes = new ArrayList<Clientes>();

try{
QueryBuilder<Clientes, Integer> queryBuilder = dao.queryBuilder();
queryBuilder.orderBy("nome", false);
clientes = dao.query(queryBuilder.prepare());
}catch(Exception e){
e.printStackTrace();
}

return clientes;
}




A única coisa que muda nesse caso é que chamamos o método "orderBy" que recebe os parâmetros do campo que será ordenado e se ele será "asc" ou "desc". (crescente ou decrescente).


Passo 3. Misturando as coisas

Digamos agora que eu quero o último registro da tabela clientes, como faço?
Notem a facilidade.


public Clientes getLast() {
Clientes cliente = new Clientes();

try{
QueryBuilder<Clientes, Integer> queryBuilder = dao.queryBuilder();
queryBuilder.orderBy("id", true);
cliente = dao.queryForFirst(queryBuilder.prepare());
}catch(Exception e){
e.printStackTrace();
}

return cliente;
}


Fazemos uma query que ordena pelo campo id de forma invertida(trazendo o último até o primeiro) e por fim pegamos o primeiro registro disponível que seria o último inserido.
Pouco código e tudo o que precisamos na mão.


Passo 4. Criando a classe para fazer o join

Vamos supôr que nosso cliente tenha vários endereços que estão armazenados em outra tabela.
Crie no seu package entities a classe Enderecos. (no meu caso, br.com.exemplo.db.entities)


@Entity(name="enderecos")
public class Enderecos {

@Id @GeneratedValue
private int id;

@Column(name="endereco", nullable=false)
private String endereco;

@Column(name="cep", nullable=false)
private String cep;

@DatabaseField(foreign=true)
private Clientes clientes;

public Enderecos() {

}

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getCep() {
return cep;
}

public void setCep(String cep) {
this.cep = cep;
}

public Clientes getClientes() {
return clientes;
}

public void setClientes(Clientes clientes) {
this.clientes = clientes;
}

public String getEndereco() {
return endereco;
}

public void setEndereco(String endereco) {
this.endereco = endereco;
}

}


Notem que temos um campo diferente dessa vez !
O campo DataBaseField indica uma FK para a tabela Clientes.
Atenção, a notação DataBaseField é do componente ORMLite e não da JPA.
Se você me perguntar o por que, tenho uma boa resposta.
Nem todas as notações JPA estão disponíveis na ferramenta ORMLite.  =(


Passo 5. Inserindo a tabela na criação da database

Abra o arquivo DataBaseHelper no package connection. (no meu caso br.com.exemplo.db.connection).
Iremos acrescentar a tabela Enderecos como mostrado abaixo.


public class DataBaseHelper<E> extends OrmLiteSqliteOpenHelper {

public DataBaseHelper(Context context) {
super(context, "sistema.db", null, 1);
}

@Override
public void onCreate(SQLiteDatabase db, ConnectionSource src) {
try{
TableUtils.createTable(src, Clientes.class);
TableUtils.createTable(src, Enderecos.class);
}catch(Exception e){
e.printStackTrace();
}
}

@Override
public void onUpgrade(SQLiteDatabase db, ConnectionSource src, int oldVersion, int newVersion) {
try{
TableUtils.dropTable(src, Clientes.class, true);
TableUtils.dropTable(src, Enderecos.class, true);
onCreate(db, src);
}catch(Exception e){
e.printStackTrace();
}
}

@Override
public void close() {
super.close();
}

}


Inserimos uma linha para Create e outra para Upgrade. Nenhum segredo. :)



Passo 6. Criando um DAO para Enderecos

Crie uma classe chamada EnderecosDAO no seu package dao (no meu caso, br.com.exemplo.db.dao)
Faça a implementação como exemplificado.


public class EnderecosDAO extends GenericDao<Enderecos> {

public EnderecosDAO(Context context) {
super(context, Enderecos.class);
}

}



Segue o mesmo modelo de implementação que fizemos no artigo anterior.



Passo 7. Inserindo a referência em Clientes

Precisamos agora inserir a referência no objeto Clientes, ou seja, quando carregarmos um cliente, automaticamente ele deverá carregar uma lista de enderecos. (join)
Abra o arquivo Clientes na pasta entities (no meu caso, br.com.exemplo.db.entities) e faça a modificação conforme demonstrado.


@Entity(name="clientes")
public class Clientes {

    @Id @GeneratedValue
private int id;

    @Column(name="nome", nullable=false)
private String nome;

    @Column(name="sobrenome", nullable=false)
private String sobrenome;

    @Column(name="email", nullable=false)
private String email;
    
    @ForeignCollectionField(eager=false)
    private Collection<Enderecos> enderecos;

public Clientes() {

}

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getNome() {
return nome;
}

public void setNome(String nome) {
this.nome = nome;
}

public String getSobrenome() {
return sobrenome;
}

public void setSobrenome(String sobrenome) {
this.sobrenome = sobrenome;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

public Collection<Enderecos> getEnderecos() {
return enderecos;
}

public void setEnderecos(Collection<Enderecos> enderecos) {
this.enderecos = enderecos;
}
}


A notação ForeignCollectionField (também da ORMLite e não JPA) faz todo o trabalho.
Ela indica que uma coleção de Enderecos será carregado de forma síncrona(eager=false) toda vez que o objeto Clientes for carregado.


Passo 8. Testando tudo



Antes de testar esse exemplo, remova completamente o aplicativo usado no artigo anterior, ok?
Abra a sua Activity e crie um método como o demonstrado.


    private void testarDB() {
    ClientesDAO daoCli = new ClientesDAO(getApplicationContext());
    Clientes cliente = new Clientes();
    cliente.setNome("StrangerDroid");
    cliente.setSobrenome("Blog");
    cliente.setEmail("strangerdroid@gmail.com");
   
    daoCli.insert(cliente);
    cliente = daoCli.getById(1);
   
    EnderecosDAO daoEnd = new EnderecosDAO(getApplicationContext());
    Enderecos endereco1 = new Enderecos();
    endereco1.setEndereco("Rua da casa");
    endereco1.setCep("234324");
    endereco1.setClientes(cliente);
   
    Enderecos endereco2 = new Enderecos();
    endereco2.setEndereco("Rua da outra casa");
    endereco2.setCep("454545");
    endereco2.setClientes(cliente);
   
    daoEnd.insert(endereco1);
    daoEnd.insert(endereco2);
   
    Clientes clientes = daoCli.getLast();
   
    if (clientes.getEnderecos() != null) {
    Toast.makeText(getApplicationContext(), Integer.toString(clientes.getEnderecos().size()), Toast.LENGTH_LONG).show();
    }


Esse método é responsável por:
- Inserir um cliente chamado "StrangerDroid"
- Inserir dois endereços para esse cliente
- Carregar novamente esse cliente.

E por último ele exibe o número de endereços do usuário.
Se tudo correu bem, ele deve exibir o numero 2 ! :) (dois endereços para o cliente "StrangerDroid")
Quando carregamos o cliente, ele trouxe os endereços. (join)
Talvez você esteja se perguntando: "Legal, mas como uso uma Collection?".
Muito simples, List<Enderecos> enderecos = new ArrayList<SuaCollection>() ; e seja feliz. rs

Aos que tiverem dúvidas, entrem em contato no endereço strangerdroid@gmail.com
Um abraço a todos e nos vemos na próxima.

StrangerDroid




2 comentários:

  1. Cara, muito bom este exemplo, parabéns, vou utilizado ainda hoje no meu novo projeto para o Google Play.

    ResponderExcluir
  2. Tem com postar o projeto completo. Sou novo no android e estou tendo problemas.
    Grato.
    Sampaio

    ResponderExcluir