Incluir resultSets em uma List através de DAO com join entre tabelas

8 respostas
jMarcel

Pessoal,

Criei 3 tabelas (USUARIOS, DISCIPLINAS e NOTAS) c/ seus relacionamentos (chave primaria, estrangeira etc).

Em uma classe NotasDAO, por ex., há 1 método listarNotas que traz: o nome (do usuário que deu a nota), a nota e a disciplina.
Para obter esses dados montei a query com join entre as tabelas (vide abaixo).

Como eu faço para incluir resultSets em uma List proveniente de 2 ou mais tabelas atravé de DAO ?

Segue o trecho do código:

public List<Notas> listaNotas() { List<Notas> nota = new ArrayList<Notas>(); if (abreConexao()) { try { st = cn.prepareStatement("SELECT USUARIO, DISCIPLINA, NOTA " + "FROM atividade01.notas y inner join atividade01.usuarios " + "on id_usuario=id_aluno inner join atividade01.disciplinas x " + "on x.id_disciplina=y.id_disciplina where y.id_aluno=?"); rs = st.executeQuery(); while (rs.next()) { Notas nt = new Notas(); nt.setUsuario(rs.getString("USUARIO")); //setUsuario e setDisciplina nao existem no bean Notas. O que posso fazer aqui ? Crio 1 bean e nt.setDisciplina(rs.getString("DISCIPLINA"));//uso o setter dele, por ex. 1 bean que relaciona os atributos das tables envolvidas ? nt.setNota(rs.getDouble("NOTA")); nota.add(nt); } } catch (Exception ex) { erro = ex.getMessage(); } finally { fechaConexao(); } } return nota; }

Se alguém tiver algum exemplo de código seria ótimo.

Agradeço pela atenção.

8 Respostas

E

Não entendi bem a pergunta, afinal, você já faz o add ali não? Bastaria ir adicionando os elementos na lista usando o add da mesma forma que você faz.

Mas eu recomendaria você usar o union all do SQL para diminuir a quantidade de consultas no servidor (isso torna a aplicação mais rápida), e se for uma quantidade muito grande de registros, melhor trabalhar com eles direto no resultSet ao invés de mover a uma List, pois a List está na memória, o resultSet na verdade é um cursor no banco de dados e traz as informações sob demanda.

jMarcel
evefuji:
Não entendi bem a pergunta, afinal, você já faz o add ali não? Bastaria ir adicionando os elementos na lista usando o add da mesma forma que você faz.

Mas eu recomendaria você usar o union all do SQL para diminuir a quantidade de consultas no servidor (isso torna a aplicação mais rápida), e se for uma quantidade muito grande de registros, melhor trabalhar com eles direto no resultSet ao invés de mover a uma List, pois a List está na memória, o resultSet na verdade é um cursor no banco de dados e traz as informações sob demanda.

Pensei um pouco mais e fiz o seguinte: criei um POJO apenas com os atributos alvo (usuario, disciplina e nota). Depoi criei um Dao de forma que fosse possível usar o set deles e incluí-los na List. (Inclusive esse 'mecanismo' é usado pelo Hibernate).
public class DaoPojoJoin extends Dao {

    public List<PojoJoin> listaNotas() {
        List<PojoJoin> nota = new ArrayList<PojoJoin>();
        if (abreConexao()) {
            try {
                st = cn.prepareStatement("SELECT USUARIO, DISCIPLINA, NOTA FROM atividade01.notas x "
                        + "right outer join atividade01.usuarios y on x.id_aluno=y.id_usuario "
                        + "right outer join atividade01.disciplinas z on x.id_disciplina=z.id_disciplina "
                        + "where id_aluno=?"); // como fazer p/ filtrar pelo usuário que está logado ? servlet ?
                rs = st.executeQuery();
                while (rs.next()) {
                    PojoJoin pj = new PojoJoin();
                    rs.getString("USUARIO");
                    rs.getString("DISCIPLINA");
                    rs.getDouble("NOTA");
                    pj.setUsuario(rs.getString("USUARIO"));
                    pj.setDisciplina(rs.getString("DISCIPLINA"));
                    pj.setNota(rs.getDouble("NOTA"));
                    nota.add(pj);
                }
            } catch (Exception ex) {
                erro = ex.getMessage();
            } finally {
                fechaConexao();
            }
        }
        return nota;
    }
}

Mas agora surgiu outra dúvida: a consulta quando executada no banco está correta, ou seja, obtenho os dados apenas de um determinado aluno (...where id_aluno=?).
Mas quando a consulta é efetuada pela aplicação, a tabela retorna vazia. Creio que o parâmetro (? --> id_aluno que logou) não está sendo passado para fazer a consulta. Como faço pra isso acontecer ? Salvo o atributo da sessão em uma variável ?

E

a List está vazia porque a consulta não está sendo executada (pelo código que vc postou aí). Provavelmente está dando erro de parâmetro não enviado.

Antes do executeQuery, você tem que passar o parâmetro que deseja, algo assim:

st = cn.prepareStatement("SELECT USUARIO, DISCIPLINA, NOTA FROM atividade01.notas x "  
                        + "right outer join atividade01.usuarios y on x.id_aluno=y.id_usuario "  
                        + "right outer join atividade01.disciplinas z on x.id_disciplina=z.id_disciplina "  
                        + "where id_aluno=?"); // como fazer p/ filtrar pelo usuário que está logado ? servlet ?  
                st.setInteger(1, idUsuario); // o "1" é o índice que deseja inserir o parâmetro, nesse caso, é o primeiro "?"
                rs = st.executeQuery();

Tem vários métodos para inserção de dados nos parâmetros, dá uma olhada aqui na documentação: http://docs.oracle.com/javase/1.4.2/docs/api/java/sql/PreparedStatement.html (documentação antiga, mas não muda essa classe para as versões atuais)

jMarcel

evefuji:
a List está vazia porque a consulta não está sendo executada (pelo código que vc postou aí). Provavelmente está dando erro de parâmetro não enviado.

Antes do executeQuery, você tem que passar o parâmetro que deseja, algo assim:

st = cn.prepareStatement("SELECT USUARIO, DISCIPLINA, NOTA FROM atividade01.notas x "  
                        + "right outer join atividade01.usuarios y on x.id_aluno=y.id_usuario "  
                        + "right outer join atividade01.disciplinas z on x.id_disciplina=z.id_disciplina "  
                        + "where id_aluno=?"); // como fazer p/ filtrar pelo usuário que está logado ? servlet ?  
                st.setInteger(1, idUsuario); // o "1" é o índice que deseja inserir o parâmetro, nesse caso, é o primeiro "?"  --> é setInt(...), só pra te lembrar
                rs = st.executeQuery();

Tem vários métodos para inserção de dados nos parâmetros, dá uma olhada aqui na documentação: http://docs.oracle.com/javase/1.4.2/docs/api/java/sql/PreparedStatement.html (documentação antiga, mas não muda essa classe para as versões atuais)

É verdade. Li ontem mesmo sobre isso em http://docs.oracle.com/javase/tutorial/jdbc/basics/prepared.html. Mesmo assim foi bom você me confirmar isso.

Mas agora eu quero settar no prepareStatement o usuário que foi validado pelo servlet.
Como faço para atribuir esse usuário da sessão ? O que posso usar ? st.setString(1,session.getAttribute(nome)); ou st.setString(1,request.getParameter("nome"));? Ou o que ?
Resumindo, como recupero o nome do usuário da sessão e o transfiro para o preparedStatement no dao ?

Obrigado pela ajuda.

jMarcel

jMarcel:
evefuji:
a List está vazia porque a consulta não está sendo executada (pelo código que vc postou aí). Provavelmente está dando erro de parâmetro não enviado.

Antes do executeQuery, você tem que passar o parâmetro que deseja, algo assim:

st = cn.prepareStatement("SELECT USUARIO, DISCIPLINA, NOTA FROM atividade01.notas x "  
                        + "right outer join atividade01.usuarios y on x.id_aluno=y.id_usuario "  
                        + "right outer join atividade01.disciplinas z on x.id_disciplina=z.id_disciplina "  
                        + "where id_aluno=?"); // como fazer p/ filtrar pelo usuário que está logado ? servlet ?  
                st.setInteger(1, idUsuario); // o "1" é o índice que deseja inserir o parâmetro, nesse caso, é o primeiro "?"  --> é setInt(...), só pra te lembrar
                rs = st.executeQuery();

Tem vários métodos para inserção de dados nos parâmetros, dá uma olhada aqui na documentação: http://docs.oracle.com/javase/1.4.2/docs/api/java/sql/PreparedStatement.html (documentação antiga, mas não muda essa classe para as versões atuais)

É verdade. Li ontem mesmo sobre isso em http://docs.oracle.com/javase/tutorial/jdbc/basics/prepared.html. Mesmo assim foi bom você me confirmar isso.

Mas agora eu quero settar no prepareStatement o usuário que foi validado pelo servlet.
Como faço para atribuir esse usuário da sessão ? O que posso usar ? st.setString(1,session.getAttribute(nome)); ou st.setString(1,request.getParameter("nome"));? Ou o que ?
Resumindo, como recupero o nome do usuário da sessão e o transfiro para o preparedStatement no dao ?

Obrigado pela ajuda.

Pesquisei e encontrei que através de getRequestDispatcher() é possível passar o controle para um outro recurso ou p/ incluir o conteúdo de um outro recurso no chamador. Estou no caminho certo ? Mas como fazer na prática ?

E

como vc está colocando o usuário na sessão? Está colocando um objeto de classe, por exemplo, usuário? Se for esse o caso, você precisaria fazer algo como:

st.setInteger(1, ((Usuario)session.getAttribute("usuario logado")).getId());  // Precisa pegar o id do usuário
jMarcel

evefuji:
como vc está colocando o usuário na sessão? Está colocando um objeto de classe, por exemplo, usuário? Se for esse o caso, você precisaria fazer algo como:

st.setInteger(1, ((Usuario)session.getAttribute("usuario logado")).getId()); // Precisa pegar o id do usuário

Estou colocando o usuário na sessão através de um ServletLogin.
O valor de session (=javax.servlet.http.HttpSession) é um request da sessão no parâmetro do método doPost.

Só pra confirmar: o DAO consegue recuperar esse atributo da session se ‘comunicando’ com o webserver, que cria e gerencia a webapp, correto ?

No BD o usuário é uniqueKey, então não tem problema pegar pelo nome do usuário - também.

Eu usei:

Porém não está funcionado. O netbeans não encontra a variável session e sugere criar uma classe session no pacote.

O que posso fazer ?

E

Pode colocar o trecho que está colocando o usuário na sessão?

Está usando que framework mvc? Se estiver direto no servlet, você pode buscar o session assim:

Criado 25 de maio de 2012
Ultima resposta 29 de mai. de 2012
Respostas 8
Participantes 2