DepartamentoProdutoDAO novo arquivo

0:00 / 0:00

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.

CÓDIGO COMPLETO
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();
    }

}
Hierarquia: de onde vêm os métodos?

O DAO herda em dois níveis:

JasapDAO (Jasap) → AppsRootDAO (projeto) → DepartamentoProdutoDAO

ClasseO que fornece
JasapDAOselect(), insert(), update(), delete(), setManager(), setDataBase(), getDataBase() — operações básicas de banco
AppsRootDAOgetFactory() — 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.

Por que dois construtores? (e o Bean/WBean não tem nenhum)

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:

ConstrutorQuem chamaPara 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.

Por que 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.

O que é 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.

O que é o alias 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 a

Aqui 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.

O que é <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.

O que 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:

  1. Substitui o placeholder <orderby> pela ordem definida no JasapList
  2. Aplica paginação automática (LIMIT/OFFSET) com base na página atual da listagem
  3. Executa a query no banco e prepara o cursor pra leitura

Depois disso, o DAO pode iterar com while (query.next()) pra ler linha por linha.

O que é 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:

  1. Olha a primeira coluna do resultado: id_produto
  2. Procura no Bean um método chamado setId_produto
  3. Achou — invoca passando o valor que veio do banco
  4. Repete pra cada coluna

Por 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.

Por que 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

ElementoO que significa
publicVisível para o Model (que estende este DAO) e pra MdFactory (que instancia)
DepartamentoProdutoDAOConvenção do projeto: prefixo do módulo + entidade + DAO
extends AppsRootDAOHerda toda infraestrutura de banco: select(), setManager(), setDataBase(), getDataBase(), getFactory(), getUser()

DepartamentoProdutoDAO() / DepartamentoProdutoDAO(AppManager)

ConstrutorPara 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

LinhaO 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_produtosetId_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