Tutorial de hibernação de muitos para muitos

Tutorial de hibernação de muitos para muitos

1. Introdução

Neste tutorial rápido, daremos uma olhada rápida em como a anotação@ManyToMany pode ser usada para especificar este tipo de relacionamento no Hibernate.

2. Um exemplo típico

Vamos começar com um diagrama de relacionamento de entidade simples - que mostra a associação muitos-para-muitos entre duas entidadesemployeeeproject:

image

Nesse cenário, qualqueremployee fornecido pode ser atribuído a vários projetos e umproject pode ter vários funcionários trabalhando para ele, levando a uma associação muitos para muitos entre os dois.

Temos uma tabelaemployee comemployee_id como sua chave primária e uma tabelaproject comproject_id como sua chave primária. Uma tabela de junçãoemployee_project é necessária aqui para conectar os dois lados.

3. Configuração do banco de dados

Vamos supor que temos um banco de dados já criado com o nomespring_hibernate_many_to_many.

Também precisamos criar as tabelasemployeeeproject junto com a tabela de junçãoemployee_project comemployee_ideproject_id como chaves estrangeiras:

CREATE TABLE `employee` (
  `employee_id` int(11) NOT NULL AUTO_INCREMENT,
  `first_name` varchar(50) DEFAULT NULL,
  `last_name` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`employee_id`)
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8;

CREATE TABLE `project` (
  `project_id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`project_id`)
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8;

CREATE TABLE `employee_project` (
  `employee_id` int(11) NOT NULL,
  `project_id` int(11) NOT NULL,
  PRIMARY KEY (`employee_id`,`project_id`),
  KEY `project_id` (`project_id`),
  CONSTRAINT `employee_project_ibfk_1`
   FOREIGN KEY (`employee_id`) REFERENCES `employee` (`employee_id`),
  CONSTRAINT `employee_project_ibfk_2`
   FOREIGN KEY (`project_id`) REFERENCES `project` (`project_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Com o banco de dados configurado, o próximo passo seria a preparação das dependências do Maven e da configuração do Hibernate. Para obter informações sobre isso, consulte o artigo emGuide to Hibernate4 with Spring

4. As classes modelo

As classes de modeloEmployeeeProject precisam ser criadas com anotações JPA:

@Entity
@Table(name = "Employee")
public class Employee {
    // ...

    @ManyToMany(cascade = { CascadeType.ALL })
    @JoinTable(
        name = "Employee_Project",
        joinColumns = { @JoinColumn(name = "employee_id") },
        inverseJoinColumns = { @JoinColumn(name = "project_id") }
    )
    Set projects = new HashSet<>();

    // standard constructor/getters/setters
}
@Entity
@Table(name = "Project")
public class Project {
    // ...

    @ManyToMany(mappedBy = "projects")
    private Set employees = new HashSet<>();

    // standard constructors/getters/setters
}

Como podemos ver,both the Employee class and Project classes refer to one another, which means that the association between them is bidirectional.

Para mapear uma associação muitos para muitos, usamos as anotações@ManyToMany,@JoinTablee@JoinColumn. Vamos dar uma olhada neles.

A anotação@ManyToMany é usada em ambas as classes para criar o relacionamento muitos-para-muitos entre as entidades.

This association has two sides i.e. the owning side and the inverse side. Em nosso exemplo, o lado proprietário éEmployee, portanto, a tabela de junção é especificada no lado proprietário usando a anotação@JoinTable na classeEmployee. O@JoinTable é usado para definir a tabela de junção / link. Neste caso, éEmployee_Project.

A anotação@JoinColumn é usada para especificar a coluna de junção / vinculação com a tabela principal. Aqui, a coluna de junção éemployee_ideproject_id é a coluna de junção inversa, poisProject está no lado inverso do relacionamento.

Na classeProject, o atributomappedBy é usado na anotação@ManyToMany para indicar que a coleçãoemployees é mapeada pela coleçãoprojects do lado do proprietário .

5. Execução

Para ver a anotação muitos-para-muitos em ação, podemos escrever o seguinte teste JUnit:

public class HibernateManyToManyAnnotationMainIntegrationTest {
    private static SessionFactory sessionFactory;
    private Session session;

    // ...

    @Test
    public void givenData_whenInsert_thenCreatesMtoMrelationship() {
        String[] employeeData = { "Peter Oven", "Allan Norman" };
        String[] projectData = { "IT Project", "Networking Project" };
        Set projects = new HashSet<>();

        for (String proj : projectData) {
            projects.add(new Project(proj));
        }

        for (String emp : employeeData) {
            Employee employee = new Employee(emp.split(" ")[0],
              emp.split(" ")[1]);

            assertEquals(0, employee.getProjects().size());
            employee.setProjects(projects);
            session.persist(employee);

            assertNotNull(employee);
        }
    }

    @Test
    public void givenSession_whenRead_thenReturnsMtoMdata() {
        @SuppressWarnings("unchecked")
        List employeeList = session.createQuery("FROM Employee")
          .list();

        assertNotNull(employeeList);

        for(Employee employee : employeeList) {
            assertNotNull(employee.getProjects());
        }
    }

    // ...
}

Podemos ver o relacionamento muitos para muitos entre as duas entidades criadas no banco de dados: as tabelasemployee,project eemployee_project com dados de amostra que representam o relacionamento.

6. Conclusão

Neste tutorial, vimos como criar mapeamentos usando as anotações muitos-para-muitos do Hibernate, que é uma contrapartida mais conveniente em comparação com a criação de arquivos de mapeamento XML.

O código-fonte deste tutorial pode ser encontradoover on GitHub.