O DAO (Data Access Object) é a peça que SABE FALAR COM O ALMOXARIFADO. É aqui que mora a query SELECT que busca os produtos no banco de dados. Terceiro arquivo da sequência CRUD READ — depende do Bean (a ficha que vai ser preenchida) e do WBean (a ficha de filtro).
Nota: nesta fase CRUD READ, o DAO tem apenas o método daoList (busca a lista de produtos). Os métodos de buscar um único registro, inserir, atualizar e deletar vão ser adicionados nas próximas sequências (DELETE, CREATE, UPDATE), conforme aparecerem as necessidades.
package br.xt.app.departamento.produto;
import br.jasap.core.AppManager;
import br.jasap.dao.Query;
import br.jasap.util.JasapList;
import br.xt.AppsRootDAO;
public class DepartamentoProdutoDAO extends AppsRootDAO {
public DepartamentoProdutoDAO() {
}
public DepartamentoProdutoDAO(AppManager manager) {
setManager(manager);
setDataBase(manager.getDataBase());
}
public void daoList(JasapList list) throws Exception {
StringBuilder sql = new StringBuilder();
sql.append("select a.* from " + DepartamentoProdutoBean.TABLE + " a <orderby>");
Query query = getDataBase().getQuery(sql.toString());
select().executeList(query, list);
while (query.next()) {
DepartamentoProdutoBean bean = new DepartamentoProdutoBean();
query.populateBean(bean);
list.getList().add(bean);
}
query.release();
}
}
O DAO herda em dois níveis:
JasapDAO (Jasap) → AppsRootDAO (projeto) → DepartamentoProdutoDAO
| Classe | O que fornece |
|---|---|
JasapDAO | select(), insert(), update(), delete(), setManager(), setDataBase(), getDataBase() — operações básicas de banco |
AppsRootDAO | getFactory() — acesso a MdFactories de outros módulos; getUser() — usuário logado; ok() — verificar permissão |
Quando o DAO chama select().executeList(query, list), o select() vem do JasapDAO. O DAO da entidade NÃO implementa nada de SQL básico — herda tudo.
O Bean e o WBean não declaram construtores — o Java cria um vazio automaticamente. Funciona porque são só objetos de dados sem dependências.
O DAO precisa de dois construtores explícitos:
| Construtor | Quem chama | Para quê |
|---|---|---|
DepartamentoProdutoDAO() | Jasap (reflection) | O framework pode precisar instanciar o DAO via Class.newInstance() em algumas operações — sem construtor vazio, falha em runtime |
DepartamentoProdutoDAO(AppManager) | Model (super(manager)) | Configura setManager() + setDataBase() — sem isso, o DAO não tem conexão com o banco |
Corrente de criação: MdFactory → Model → super(manager) → DAO configurado com conexão ao banco.
throws Exception em vez de tratar?
Qualquer chamada de banco pode lançar SQLException (conexão caiu, query inválida, FK quebrada, etc.). O DAO PODERIA capturar com try/catch — mas não é o lugar certo de tratar.
O throws Exception deixa a exceção SUBIR pelo código. Quem captura no fim é um filtro global do framework (ErrorFilter), que registra o erro e mostra uma tela amigável pro usuário.
Vantagem: o DAO fica focado SÓ em falar com o banco. Tratamento de erro é responsabilidade de outra camada.
StringBuilder? (áudio dedicado)
Em Java, String é imutável — cada concatenação com + cria um objeto novo. Pra montar SQL grande com várias partes, isso vira desperdício de memória.
StringBuilder é uma classe que permite ir adicionando texto SEM criar objeto novo a cada passo. No fim, toString() devolve a string final.
No daoList a montagem é simples (basicamente um append), mas a convenção do projeto é usar StringBuilder sempre que monta SQL — porque em DAOs com filtros condicionais, vão aparecer vários append consecutivos.
Áudio dedicado: tem um áudio só sobre StringBuilder no card Fundamentos Java do estudo, explicando em profundidade por que String é imutável, quando usar StringBuilder vs StringBuffer, e os ganhos de performance reais.
a em from ... a?
a é um apelido (alias) da tabela. Em SQL, todo apelido depois do nome da tabela serve pra referenciar colunas qualificadas, ex: a.nome_produto.
No daoList aparece em duas linhas:
select a.* from departamento.produto a — pega todas as colunas da tabela apelidada de aAqui parece exagero (a tabela é só uma), mas a convenção do projeto é SEMPRE usar alias. Quando o DAO precisar de JOIN com outras tabelas, cada uma vai ter seu alias (a, b, c), e as referências de coluna ficam claras.
<orderby>?
<orderby> é um placeholder que o Jasap reconhece e substitui por uma cláusula ORDER BY real na hora de executar a query.
A configuração de ordem mora na ListView (a tela de listagem). Quando o usuário clica no cabeçalho de uma coluna, a ListView atualiza a ordem desejada e o DAO recebe via JasapList. O Jasap então pega essa ordem e injeta no lugar do <orderby> — algo como:
select a.* from departamento.produto a ORDER BY a.nome_produto ASC
O DAO não precisa saber qual coluna nem direção — só deixa o placeholder e o framework cuida.
select().executeList() faz?
O método select() vem do JasapDAO e devolve um objeto helper de SELECT. O executeList(query, list) faz três coisas:
<orderby> pela ordem definida no JasapListDepois disso, o DAO pode iterar com while (query.next()) pra ler linha por linha.
query.populateBean(bean)? (reflection — áudio dedicado)
O populateBean usa reflection (uma técnica do Java) pra olhar as colunas que vieram do banco e encontrar o setter correspondente em cada uma.
Fluxo:
id_produtosetId_produtoPor isso a nomenclatura JavaBean é OBRIGATÓRIA: se o setter se chamasse gravarId em vez de setId_produto, o reflection não acharia e o campo ficaria null.
Áudio dedicado: tem um áudio só sobre Reflection em Java no card Fundamentos Java do estudo, mostrando como o Java consegue olhar a estrutura de uma classe em runtime e invocar métodos pelo nome.
query.release() é obrigatório?
Cada Query abre recursos no banco: cursor, ResultSet, conexão emprestada do pool. Esses recursos precisam ser DEVOLVIDOS quando a leitura termina.
Sem query.release(), os recursos ficam pendurados. Com o tempo, o pool de conexões esgota — todo mundo tentando conectar e ninguém consegue. O sistema trava.
Por que não tem try/finally? Porque o throws Exception deixa a exceção subir pro filtro global, e em produção o framework garante que conexões órfãs sejam fechadas no fim do request via DataBaseFilter. Mas o release() explícito é a boa prática — libera ASSIM QUE o cursor termina, sem esperar o fim do request.
public class DepartamentoProdutoDAO extends AppsRootDAO| Elemento | O que significa |
|---|---|
public | Visível para o Model (que estende este DAO) e pra MdFactory (que instancia) |
DepartamentoProdutoDAO | Convenção do projeto: prefixo do módulo + entidade + DAO |
extends AppsRootDAO | Herda toda infraestrutura de banco: select(), setManager(), setDataBase(), getDataBase(), getFactory(), getUser() |
DepartamentoProdutoDAO() / DepartamentoProdutoDAO(AppManager)| Construtor | Para quê |
|---|---|
DepartamentoProdutoDAO() | Construtor vazio — exigido pelo Jasap para instanciação via reflection em alguns pontos do framework |
DepartamentoProdutoDAO(AppManager) | Construtor principal usado pelo Model. setManager(manager) grava o manager (cartão temporário); setDataBase(manager.getDataBase()) configura a conexão com o banco extraída do cartão |
daoList(JasapList list) throws Exception| Linha | O que faz |
|---|---|
StringBuilder sql = new StringBuilder() | Cria um buffer mutável pra montar o SQL sem criar objetos String intermediários |
sql.append("select a.* from " + TABLE + " a <orderby>") | Monta o SELECT usando a constante TABLE do Bean. Alias a pra qualificar colunas em joins futuros. <orderby> é placeholder que o Jasap substitui |
getDataBase().getQuery(sql.toString()) | Pega a conexão do cartão, cria o objeto Query com o SQL — ainda não executou nada no banco |
select().executeList(query, list) | Executa: substitui <orderby>, aplica paginação (LIMIT/OFFSET), abre o cursor pra leitura |
while (query.next()) | Itera o cursor — cada next() avança uma linha do resultado. Retorna false quando acabou |
new DepartamentoProdutoBean() | Cria uma ficha em branco pra cada linha do resultado |
query.populateBean(bean) | Reflection: pega cada coluna do cursor, encontra o setter correspondente no Bean (id_produto → setId_produto), invoca passando o valor |
list.getList().add(bean) | Adiciona a ficha preenchida na lista que a tela vai consumir |
query.release() | Libera os recursos do cursor de volta pro pool de conexões — obrigatório |