JDBC com relacionamento N-N

Uma dúvida recorrente entre iniciantes em programação Java e de manipulação de banco de dados é o momento que eles têm pela frente um relacionamento N-N entre tabelas. Este relacionamento por regra trabalha com uma terceira tabela, chamada de associativa. A tabela associativa é criada com o objetivo de armazenar os identificadores entre o relacionamento N-N.

Neste tutorial vamos ver um breve exemplo de como manipular tabelas como relacionamento muitos-para-muitos, utilizando Java e JDBC. Veja na Figura 1, o relacionamento entre as tabelas PROFESSORES, e CURSOS que gerou a tabela associativa PROFESSORES_CURSOS. Então, um professor poderá dar aulas em vários cursos e cada curso poderá ter vários professores. A tabela associativa tem ainda um ID próprio, o que não é obrigatório já que as chaves estrangeiras poderiam fazer esse papel, e também a coluna TURNO.

Figura 1 - Diagrama E.R.

Figura 1 – Diagrama E.R.

O script do banco de dados pode ser visualizado a seguir:

-- phpMyAdmin SQL Dump
-- version 3.3.9
-- http://www.phpmyadmin.net
--

SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;

--
-- Banco de Dados: `cursodb`
--

--
-- Estrutura da tabela `cursos`
--

CREATE TABLE IF NOT EXISTS `cursos` (
  `ID_CURSO` int(11) NOT NULL AUTO_INCREMENT,
  `CURSO` varchar(50) NOT NULL,
  PRIMARY KEY (`ID_CURSO`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=0;

--
-- Estrutura da tabela `professores`
--

CREATE TABLE IF NOT EXISTS `professores` (
  `ID_PROFESSOR` int(11) NOT NULL AUTO_INCREMENT,
  `NOME` varchar(50) NOT NULL,
  PRIMARY KEY (`ID_PROFESSOR`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=0;

--
-- Estrutura da tabela `professores_cursos`
--

CREATE TABLE IF NOT EXISTS `professores_cursos` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `TURNO` varchar(10) NOT NULL,
  `ID_PROFESSOR` int(11) NOT NULL,
  `ID_CURSO` int(11) NOT NULL,
  PRIMARY KEY (`ID`),
  KEY `FK_ID_PROFESSOR` (`ID_PROFESSOR`),
  KEY `FK_ID_CURSO` (`ID_CURSO`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=0;

Agora que já conhecemos os relacionamentos no banco de dados, vamos partir para o código Java. As classes de entidades serão Professor (Listagem 1), Curso (Listagem 2) e ProfessorCurso (Listagem 3). Ainda teremos um enumerado na Listagem 4, para manipulação dos turnos.

Listagem 1. Classe Professor
package com.wp.mballem.tutorial.entidade;

/**
 * http://www.mballem.com/
 */
public class Professor {
    private int idProfessor;
    private String nome;

    public Professor() {
    }

    public Professor(String nome) {
        this.nome = nome;
    }

    //gere os métodos get/set

    @Override
    public String toString() {
        return "Professor{" +
                "idProfessor=" + idProfessor +
                ", nome='" + nome + '\'' +
                '}';
    }
}
Listagem 2. Classe Curso
package com.wp.mballem.tutorial.entidade;

/**
 * http://www.mballem.com/
 */
public class Curso {
    private int idCurso;
    private String curso;

    public Curso() {
    }

    public Curso(String curso) {
        this.curso = curso;
    }

    //Gere os métodos get/set

    @Override
    public String toString() {
        return "Curso{" +
                "idCurso=" + idCurso +
                ", curso='" + curso + '\'' +
                '}';
    }
}
Listagem 3. Classe ProfessorCurso
package com.wp.mballem.tutorial.entidade;

/**
 * http://www.mballem.com/
 */
public class ProfessorCurso {
    private int id;
    private int idProfessor;
    private int idCurso;
    private String turno;

    public ProfessorCurso() {
    }

    public ProfessorCurso(int idProfessor, int idCurso, String turno) {
        this.idProfessor = idProfessor;
        this.idCurso = idCurso;
        this.turno = turno;
    }

    //Gere os métodos get/set

    @Override
    public String toString() {
        return "ProfessorCurso{" +
                "id=" + id +
                ", idProfessor=" + idProfessor +
                ", idCurso=" + idCurso +
                ", turno='" + turno + '\'' +
                '}';
    }
}
Listagem 4. enum Turno
package com.wp.mballem.tutorial.entidade;

/**
 * http://www.mballem.com/
 */
public enum Turno {
    M(0,"Manhã"), T(1,"Tarde"), N(2,"Noite");

    private int indice;
    private String descricao;

    Turno(int indice, String descricao) {
        this.indice = indice;
        this.descricao = descricao;
    }

    public int getIndice() {
        return indice;
    }

    public String getDescricao() {
        return descricao;
    }
}

Vamos agora para a parte de persistência, para isso, será usado o padrão DAO. Primeiro vamos adicionar ao projeto uma classe de conexão, conforme a Listagem 5. Tal classe está configurada para acessar um banco de dados MySql, então adicione ao seu projeto o Driver de conexão do MySql. Esta classe possui dois métodos estáticos, open() para abrir a conexão com o banco de dados e o close() para fechar as operações com o banco.

Listagem 5. Classe de conexão
package com.wp.mballem.tutorial.dao;

import java.sql.*;

/**
 * http://www.mballem.com/
 */
public class Conexao {
    private static final String DRIVER = "com.mysql.jdbc.Driver";
    private static final String URL = "jdbc:mysql://localhost/cursodb";
    private static final String USER = "root";
    private static final String PASS = "";

    public static Connection open() {
        try {
            Class.forName(DRIVER);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        Connection conn = null;
        try {
            conn = DriverManager.getConnection(URL, USER, PASS);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return conn;
    }

    public static void close(Connection conn,
                             PreparedStatement pstm, ResultSet rs)
    {
        try {
            if (conn != null) {
                conn.close();
            }
            if (pstm != null) {
                pstm.close();
            }
            if (rs != null) {
               rs.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

Na Listagem 6 temos a interface IDAO, a qual deverá ser implementada nas classes concretas de cada DAO específico de cada entidade. A princípio, teremos apenas três métodos nessa interface, o método save() para inserir dados no banco, o método findMaxId() para recuperar o último ID inserido em cada tabela e por fim o método findAll() para listar todas as linhas de cada tabela.

Listagem 6. Interface IDAO.
package com.wp.mballem.tutorial.dao;

import java.util.List;

/**
 * http://www.mballem.com/
 */
public interface IDAO {
    void save(T entidade);
    int findMaxId();
    List findAll();
}

Confira na Listagem 7 a classe de persistência ProfessorDAO. Além dos métodos da interface IDAO, a classe possui o método findProfByCurso() para localizar um professor através de um curso qualquer usado como parametro de busca e também contém o método findByTurno() que retorna uma lista com todos os professores que lecionam em um determinado turno.

Listagem 7. Classe ProfessorDAO
package com.wp.mballem.tutorial.dao;

import com.wp.mballem.tutorial.entidade.Professor;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * http://www.mballem.com/
 */
public class ProfessorDAO implements IDAO {

    public void save(Professor entidade) {
        Connection conn = Conexao.open();
        PreparedStatement pstm = null;
        String sql = "INSERT INTO professores (nome) VALUES (?)";
        try {
            pstm = conn.prepareStatement(sql);
            pstm.setString(1, entidade.getNome());
            pstm.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            Conexao.close(conn, pstm, null);
        }
    }

    public int findMaxId() {
        Connection conn = Conexao.open();
        PreparedStatement pstm = null;
        ResultSet rs = null;
        String sql = "SELECT MAX(id_professor) FROM professores";
        int id = 0;
        try {
            pstm = conn.prepareStatement(sql);
            rs = pstm.executeQuery();
            if (rs.next()) {
                id = rs.getInt(1);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            Conexao.close(conn, pstm, rs);
        }
        return id;
    }

    public List findAll() {
        Connection conn = Conexao.open();
        PreparedStatement pstm = null;
        ResultSet rs = null;
        String sql = "SELECT * FROM professores";
        List professorList = new ArrayList();
        Professor professor = null;
        try {
            pstm = conn.prepareStatement(sql);
            rs = pstm.executeQuery();
            while (rs.next()) {
                professor = new Professor();
                professor.setIdProfessor(rs.getInt("id_professor"));
                professor.setNome(rs.getString("nome"));

                professorList.add(professor);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            Conexao.close(conn, pstm, rs);
        }
        return professorList;
    }

    public List findProfByCurso(String curso) {
        Connection conn = Conexao.open();
        PreparedStatement pstm = null;
        ResultSet rs = null;
        String sql =
                "SELECT p.* " +
                "FROM professores p, professores_cursos pc, cursos c " +
                "WHERE c.curso = ? " +
                "AND c.id_curso = pc.id_curso " +
                "AND p.id_professor = pc.id_professor ";

        List professorList = new ArrayList();

        Professor professor = null;

        try {
            pstm = conn.prepareStatement(sql);
            pstm.setString(1, curso);
            rs = pstm.executeQuery();
            while (rs.next()) {
                professor = new Professor();
                professor.setIdProfessor(rs.getInt("id_professor"));
                professor.setNome(rs.getString("nome"));

                professorList.add(professor);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            Conexao.close(conn, pstm, rs);
        }
        return professorList;
    }

    public List findByTurno(String turno) {
        Connection conn = Conexao.open();
        PreparedStatement pstm = null;
        ResultSet rs = null;
        String sql =
                "SELECT DISTINCT(p.nome), p.id_professor " +
                "FROM professores p, professores_cursos pc " +
                "WHERE pc.turno like ? " +
                "AND pc.id_professor = p.id_professor";

        List professorList = new ArrayList();

        Professor professor = null;

        try {
            pstm = conn.prepareStatement(sql);
            pstm.setString(1, turno);
            rs = pstm.executeQuery();
            while (rs.next()) {
                professor = new Professor();
                professor.setIdProfessor(rs.getInt("id_professor"));
                professor.setNome(rs.getString("nome"));

                professorList.add(professor);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            Conexao.close(conn, pstm, rs);
        }
        return professorList;
    }
}

A classe de persistência CursoDAO possui além dos métodos definidos em sua interface IDAO, o método findCursoByProf() que retorna os cursos através do nome de um professor e também o método findByTurno() que retorna uma lista de cursos em um determinado turno.

Listagem 8. Classe CursoDAO
package com.wp.mballem.tutorial.dao;

import com.wp.mballem.tutorial.entidade.Curso;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * http://www.mballem.com/
 */
public class CursoDAO implements IDAO {

    public void save(Curso entidade) {
        Connection conn = Conexao.open();
        PreparedStatement pstm = null;
        String sql = "INSERT INTO cursos (curso) VALUES (?)";
        try {
            pstm = conn.prepareStatement(sql);
            pstm.setString(1, entidade.getCurso());
            pstm.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            Conexao.close(conn, pstm, null);
        }
    }

    public int findMaxId() {
        Connection conn = Conexao.open();
        PreparedStatement pstm = null;
        ResultSet rs = null;
        String sql = "SELECT MAX(id_curso) FROM cursos";
        int id = 0;
        try {
            pstm = conn.prepareStatement(sql);
            rs = pstm.executeQuery();
            if (rs.next()) {
                id = rs.getInt(1);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            Conexao.close(conn, pstm, rs);
        }
        return id;
    }

    public List findAll() {
        Connection conn = Conexao.open();
        PreparedStatement pstm = null;
        ResultSet rs = null;
        String sql = "SELECT * FROM cursos";
        List cursoList = new ArrayList();
        Curso curso = null;
        try {
            pstm = conn.prepareStatement(sql);
            rs = pstm.executeQuery();
            while (rs.next()) {
                curso = new Curso();
                curso.setIdCurso(rs.getInt("id_curso"));
                curso.setCurso(rs.getString("curso"));

                cursoList.add(curso);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            Conexao.close(conn, pstm, rs);
        }
        return cursoList;
    }

    public List findCursoByProf(String nomeProf) {
        Connection conn = Conexao.open();
        PreparedStatement pstm = null;
        ResultSet rs = null;
        String sql =
                "SELECT c.* " +
                "FROM professores p, professores_cursos pc, cursos c " +
                "WHERE p.nome = ? " +
                "AND p.id_professor = pc.id_professor " +
                "AND c.id_curso = pc.id_curso ";
        List cursoList = new ArrayList();
        Curso curso = null;
        try {
            pstm = conn.prepareStatement(sql);
            pstm.setString(1, nomeProf);
            rs = pstm.executeQuery();
            while (rs.next()) {
                curso = new Curso();
                curso.setIdCurso(rs.getInt("id_curso"));
                curso.setCurso(rs.getString("curso"));

                cursoList.add(curso);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            Conexao.close(conn, pstm, rs);
        }
        return cursoList;
    }

    public List findByTurno(String turno) {
        Connection conn = Conexao.open();
        PreparedStatement pstm = null;
        ResultSet rs = null;
        String sql =
                "SELECT DISTINCT(c.curso), c.id_curso " +
                "FROM cursos c, professores_cursos pc " +
                "WHERE pc.turno like ? " +
                "AND pc.id_curso = c.id_curso";
        List cursoList = new ArrayList();
        Curso curso = null;
        try {
            pstm = conn.prepareStatement(sql);
            pstm.setString(1, turno);
            rs = pstm.executeQuery();
            while (rs.next()) {
                curso = new Curso();
                curso.setIdCurso(rs.getInt("id_curso"));
                curso.setCurso(rs.getString("curso"));

                cursoList.add(curso);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            Conexao.close(conn, pstm, rs);
        }
        return cursoList;
    }
}

A classe ProfessorCursoDAO será responsável pela persistência na tabela associativa PROFESSORES_CURSOS. Os métodos disponíveis nesta classe são apenas os métodos da interface IDAO.

Listagem 9. Classe ProfessorCursoDAO
package com.wp.mballem.tutorial.dao;

import com.wp.mballem.tutorial.entidade.ProfessorCurso;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * http://www.mballem.com/
 */
public class ProfessorCursoDAO implements IDAO {
    public void save(ProfessorCurso entidade) {
        Connection conn = Conexao.open();
        PreparedStatement pstm = null;
        String sql =
                "INSERT INTO professores_cursos (turno, id_professor, id_curso)" +
                " VALUES (?,?,?)";
        try {
            pstm = conn.prepareStatement(sql);
            pstm.setString(1, entidade.getTurno());
            pstm.setInt(2, entidade.getIdProfessor());
            pstm.setInt(3, entidade.getIdCurso());
            pstm.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            Conexao.close(conn, pstm, null);
        }
    }

    public int findMaxId() {
        Connection conn = Conexao.open();
        PreparedStatement pstm = null;
        ResultSet rs = null;
        String sql = "SELECT MAX(id) FROM professores_cursos";
        int id = 0;
        try {
            pstm = conn.prepareStatement(sql);
            rs = pstm.executeQuery();
            if (rs.next()) {
                id = rs.getInt(1);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            Conexao.close(conn, pstm, rs);
        }
        return id;
    }

    public List findAll() {
        Connection conn = Conexao.open();
        PreparedStatement pstm = null;
        ResultSet rs = null;
        String sql = "SELECT * FROM professores_cursos";
        List professorCursoList = new ArrayList();
        ProfessorCurso professorCurso = null;
        try {
            pstm = conn.prepareStatement(sql);
            rs = pstm.executeQuery();
            while (rs.next()) {
                professorCurso = new ProfessorCurso();
                professorCurso.setId(rs.getInt("id"));
                professorCurso.setTurno(rs.getString("turno"));
                professorCurso.setIdProfessor(rs.getInt("id_professor"));
                professorCurso.setIdCurso(rs.getInt("id_curso"));

                professorCursoList.add(professorCurso);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            Conexao.close(conn, pstm, rs);
        }
        return professorCursoList;
    }
}

Agora vamos executar um teste de persistência através da classe TesteMain. O método save() irá salvar alguns professores no banco de dados bem como alguns cursos. Posteriormente você poderá adicionar mais professores ou mais cursos, conforme achar necessário.

Listagem 10. Classe TesteMain – Método save()
package com.wp.mballem.tutorial;

import com.wp.mballem.tutorial.dao.CursoDAO;
import com.wp.mballem.tutorial.dao.ProfessorCursoDAO;
import com.wp.mballem.tutorial.dao.ProfessorDAO;
import com.wp.mballem.tutorial.entidade.Curso;
import com.wp.mballem.tutorial.entidade.Professor;
import com.wp.mballem.tutorial.entidade.ProfessorCurso;
import com.wp.mballem.tutorial.entidade.Turno;

import java.util.List;

/**
 * http://www.mballem.com/
 */
public class TesteMain {
    public static void main(String[] args) {
        save();
        list();
    }

    private static void save() {
        //Salva o curso e recupera seu id
        Curso c1 = new Curso("Sistemas de Informação");
        new CursoDAO().save(c1);
        int idC1 = new CursoDAO().findMaxId();
        //Salva o professor e recupera seu id
        Professor p1 = new Professor("Fulano de Tal");
        new ProfessorDAO().save(p1);
        int idP1 = new ProfessorDAO().findMaxId();
        //Insere na tabela N-N o professor, o curso e o turno
        ProfessorCurso pf1 =
                new ProfessorCurso(idP1, idC1, Turno.M.getDescricao());

        new ProfessorCursoDAO().save(pf1);
        System.out.println(new ProfessorCursoDAO().findMaxId());

        //Salva novo curso e recupera seu id
        Curso c2 = new Curso("Analise de Sistemas");
        new CursoDAO().save(c2);
        int idC2 = new CursoDAO().findMaxId();
        //Insere na tabela N-N
        ProfessorCurso pf2 =
                new ProfessorCurso(idP1, idC2, Turno.M.getDescricao());

        new ProfessorCursoDAO().save(pf2);
        System.out.println(new ProfessorCursoDAO().findMaxId());

        //Salva novo professor e recupera seu id
        Professor p2 = new Professor("Beltrano de Tal");
        new ProfessorDAO().save(p2);
        int idP2 = new ProfessorDAO().findMaxId();
        //Insere na tabela N-N o novo professor no curso
        // de Analise de Sistemas e turno Manhã
        ProfessorCurso pf3 =
                new ProfessorCurso(idP2, idC2, Turno.M.getDescricao());

        new ProfessorCursoDAO().save(pf3);
        System.out.println(new ProfessorCursoDAO().findMaxId());

        //Salva novo professor e recupera seu id
        Professor p3 = new Professor("Ciclano de Tal");
        new ProfessorDAO().save(p3);
        int idP3 = new ProfessorDAO().findMaxId();
        //Salva novo curso e recupera seu id
        Curso c3 = new Curso("Ciencia da Computação");
        new CursoDAO().save(c3);
        int idC3 = new CursoDAO().findMaxId();
        //Insere na tabela N-N o novo professor, o novo curso em todos turnos
        ProfessorCurso pf4 =
                new ProfessorCurso(idP3, idC3, Turno.M.getDescricao());

        new ProfessorCursoDAO().save(pf4);
        System.out.println(new ProfessorCursoDAO().findMaxId());
        ProfessorCurso pf5 =
                new ProfessorCurso(idP3, idC2, Turno.T.getDescricao());

        new ProfessorCursoDAO().save(pf5);
        System.out.println(new ProfessorCursoDAO().findMaxId());
        ProfessorCurso pf6 =
                new ProfessorCurso(idP3, idC1, Turno.N.getDescricao());

        new ProfessorCursoDAO().save(pf6);
        System.out.println(new ProfessorCursoDAO().findMaxId());
    }
}

Agora adicione o método list() – Listagem 11 – na classe TesteMain e execute-o para que sejam listados os dados inseridos no banco de dados. Posteriormente você poderá criar qualquer outra consulta que desejar.

Listagem 11. Classe TesteMain – Método list()
private static void list() {
        //Lista todos os professores
        List professorList =
                new ProfessorDAO().findAll();
        System.out.println("1. " + professorList.toString());

        //Lista todos os cursos
        List cursoList = new CursoDAO().findAll();
        System.out.println("2. " + cursoList.toString());

        //Lista todos os professores_cursos
        List professorCursoList =
                new ProfessorCursoDAO().findAll();
        System.out.println("3. " + professorCursoList.toString());

        //Lista todos os professores por curso
        List professorList1 =
                new ProfessorDAO().findProfByCurso("Sistemas de Informação");
        System.out.println("4. " + professorList1.toString());

        //Lista todos os cursos de um professor
        List cursoList1 =
                new CursoDAO().findCursoByProf("Ciclano de Tal");
        System.out.println("5. " + cursoList1.toString());

        //Lista cursos por turno
        List cursoList2 =
                new CursoDAO().findByTurno(Turno.M.getDescricao());
        System.out.println("6. " + cursoList2.toString());

        //Lista professores por turno
        List professorList2 =
                new ProfessorDAO().findByTurno(Turno.T.getDescricao());
        System.out.println("7. " + professorList2.toString());
}

Podemos ainda incluir na entidade Professor uma lista de Cursos, onde quando se fizer uma busca por professores, o retorno já trará todos os cursos que estes lecionam. E também na entidade Curso, podemos adicionar uma lista de Professores para que na consulta de um curso, ela também retorne os professores relacionados com cada curso. Na Listagem 12, adicionamos na classe Professor uma lista de cursos e Listagem 13, adicionamos na classe Curso uma lista de professores.

Listagem 12. Classe Professor com lista de cursos.
package com.wp.mballem.tutorial.entidade;

import java.util.ArrayList;
import java.util.List;

/**
 * http://www.mballem.com/
 */
public class Professor {
    private int idProfessor;
    private String nome;

    private List cursos = new ArrayList();

    public Professor() {
    }

    public Professor(String nome) {
        this.nome = nome;
    }

    //gere os métodos get/set

    @Override
    public String toString() {
        return "Professor{" +
                "idProfessor=" + idProfessor +
                ", nome='" + nome + '\'' +
                ", cursos=" + cursos +
                '}';
    }
}
Listagem 13. Classe Curso com lista de professores
package com.wp.mballem.tutorial.entidade;

import java.util.ArrayList;
import java.util.List;

/**
 * http://www.mballem.com/
 */
public class Curso {
    private int idCurso;
    private String curso;

    private List professors = new ArrayList();

    public Curso() {
    }

    public Curso(String curso) {
        this.curso = curso;
    }

    //gere os métodos get/set

    @Override
    public String toString() {
        return "Curso{" +
                "idCurso=" + idCurso +
                ", curso='" + curso + '\'' +
                ", professors=" + professors +
                '}';
    }
}

Vá até a classe de persistecia ProfessorDAO e insiria o método listCursosByProf(). Este método irá preencher a lista de cursos através do ID de cada professor. Confira na Listagem 14 tal método e uma nova versão para o método findAll(), a qual deverá substituir a versão anterior.

Nesta nova versão, cada professor localizado terá também como resultado a lista dos cursos em que ele leciona. Para isso, usamos o método listCursosByProf() que através do parametro idProfessor faz uma consulta buscando todos os cursos referentes ao professor em questão.

Listagem 14. Classe ProfessorDAO atualizada.
private List listCursosByProf(Connection conn, int idProf) {
	String sql =
			"SELECT c.* " +
			"FROM cursos c, professores_cursos pf " +
			"WHERE pf.id_professor = ? " +
			"AND pf.id_curso = c.id_curso";
	PreparedStatement pstm = null;
	ResultSet resultSet = null;
	List cursos = new ArrayList();
	try {
		pstm = conn.prepareStatement(sql);
		pstm.setInt(1, idProf);
		resultSet = pstm.executeQuery();
		while (resultSet.next()) {
			Curso curso = new Curso();
			curso.setIdCurso(resultSet.getInt("id_curso"));
			curso.setCurso(resultSet.getString("curso"));

			cursos.add(curso);
		}
	} catch (SQLException e) {
		e.printStackTrace();
	} finally {
		Conexao.close(null, pstm, resultSet);
	}

	return cursos;
}

public List findAll() {
	Connection conn = Conexao.open();
	PreparedStatement pstm = null;
	ResultSet rs = null;
	String sql = "SELECT * FROM professores";
	List professorList = new ArrayList();
	Professor professor = null;
	try {
		pstm = conn.prepareStatement(sql);
		rs = pstm.executeQuery();
		while (rs.next()) {
			professor = new Professor();
			professor.setIdProfessor(rs.getInt("id_professor"));
			professor.setNome(rs.getString("nome"));
			professor.setCursos(
					listCursosByProf(conn, professor.getIdProfessor())
			);

			professorList.add(professor);
		}
	} catch (SQLException e) {
		e.printStackTrace();
	} finally {
		Conexao.close(conn, pstm, rs);
	}
	return professorList;
}

Na Listagem 15 teremos a mesma situação para a classe CursoDAO, insira o novo método na classe e substitua o método findAll() anterior por este novo.

Listagem 15. Classe CursoDAO atualizada.
private List listProfsByCurso(Connection conn, int idCurso) {
	String sql =
			"SELECT p.* " +
			"FROM professores p, professores_cursos pf " +
			"WHERE pf.id_curso = ? " +
			"AND pf.id_professor = p.id_professor";
	PreparedStatement pstm = null;
	ResultSet resultSet = null;
	List professores = new ArrayList();
	try {
		pstm = conn.prepareStatement(sql);
		pstm.setInt(1, idCurso);
		resultSet = pstm.executeQuery();
		while (resultSet.next()) {
			Professor prof = new Professor();
			prof.setIdProfessor(resultSet.getInt("id_professor"));
			prof.setNome(resultSet.getString("nome"));

			professores.add(prof);
		}
	} catch (SQLException e) {
		e.printStackTrace();
	} finally {
		Conexao.close(null, pstm, resultSet);
	}

	return professores;
}

public List findAll() {
	Connection conn = Conexao.open();
	PreparedStatement pstm = null;
	ResultSet rs = null;
	String sql = "SELECT * FROM cursos";
	List cursoList = new ArrayList();
	Curso curso = null;
	try {
		pstm = conn.prepareStatement(sql);
		rs = pstm.executeQuery();
		while (rs.next()) {
			curso = new Curso();
			curso.setIdCurso(rs.getInt("id_curso"));
			curso.setCurso(rs.getString("curso"));
			curso.setProfessors(
					listProfsByCurso(conn, curso.getIdCurso())
			);

			cursoList.add(curso);
		}
	} catch (SQLException e) {
		e.printStackTrace();
	} finally {
		Conexao.close(conn, pstm, rs);
	}
	return cursoList;
}

Para executar os testes, adicione na classe TesteMain o método listCollection() da Listagem 16.

Listagem 16. Classe TesteMain atualizada.
private static void listCollection() {
	List professorList = new ProfessorDAO().findAll();
	for (Professor professor : professorList) {
		System.out.println(professor.toString());
	}

	List cursoList = new CursoDAO().findAll();
	for (Curso curso : cursoList) {
		System.out.println(curso.toString());
	}
}

Conclusão

O tutorial demonstrou rapidamente um exemplo de como trabalhar em Java com tabelas associativas (N-N) usando JDBC. Espero que tenha sido útil a todos que por ventura encontravam dificuldades em trabalhar com esse tipo de relacionamento.

Saiba mais

Ballem

Marcio Ballem é bacharel em Sistemas de Informação pelo Centro Universitário Franciscano em Santa Maria/RS. Tem experiência com desenvolvimento Delphi e Java em projetos para gestão pública e acadêmica. Possui certificação em Java, OCJP 6.

Você pode gostar...