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

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.

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.

[quote=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.[/quote]

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

[code]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;
}

}
[/code]

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 ?

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)

[quote=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)[/quote]

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

[quote=jMarcel][quote=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)[/quote]

É 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.[/quote]

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 ?

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

[quote=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 [/quote]

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 ?

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: