Hibernate Many to Many Annotation Tutorial – Hibernate多对多注释教程

最后修改: 2017年 9月 1日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.介绍

In this quick tutorial, we’ll have a quick look at how the @ManyToMany annotation can be used for specifying this type of relationships in Hibernate.

在这个快速教程中,我们将快速了解@ManyToMany注解如何用于在Hibernate中指定这种类型的关系。

2. A Typical Example

2.一个典型的例子

Let’s start with a simple Entity Relationship Diagram – which shows the many-to-many association between two entities employee and project:

让我们从一个简单的实体关系图开始–它显示了两个实体employee project:之间的多对多关联。

New 300x59

In this scenario, any given employee can be assigned to multiple projects and a project may have multiple employees working for it, leading to a many-to-many association between the two.

在这种情况下,任何给定的雇员可以被分配到多个项目,而一个项目可能有多个雇员为其工作,导致两者之间存在多对多的关联。

We have an employee table with employee_id as its primary key and a project table with project_id as its primary key. A join table employee_project is required here to connect both sides.

我们有一个employee表,employee_id是其主键,还有一个project表,project_id是其主键。这里需要一个连接表employee_project来连接双方。

3. Database Setup

3.数据库的设置

Let’s assume we have an already created database with the name spring_hibernate_many_to_many.

让我们假设我们有一个已经创建的数据库,名称为spring_hibernate_many_to_many.

We also need to create the employee and project tables along with the employee_project join table with employee_id and project_id as foreign keys:

我们还需要创建employeeproject表,以及employee_project连接表,employee_idproject_id作为外键。

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;

With the database set up, next step would be the preparation of the Maven dependencies and Hibernate configuration. For information on this, please refer to the article on Guide to Hibernate4 with Spring

在建立了数据库之后,下一步将是准备Maven的依赖性和Hibernate的配置。有关这方面的信息,请参考Guide to Hibernate4 with Spring上的文章。

4. The Model Classes

4.模型类

The model classes Employee and Project need to be created with JPA annotations:

模型类EmployeeProject需要用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<Project> projects = new HashSet<>();
   
    // standard constructor/getters/setters
}
@Entity
@Table(name = "Project")
public class Project {    
    // ...  
 
    @ManyToMany(mappedBy = "projects")
    private Set<Employee> employees = new HashSet<>();
    
    // standard constructors/getters/setters   
}

As we can see, both the Employee class and Project classes refer to one another, which means that the association between them is bidirectional.

正如我们所看到的,雇员类和项目类都互相引用,这意味着它们之间的关联是双向的。

In order to map a many-to-many association, we use the @ManyToMany, @JoinTable and @JoinColumn annotations. Let’s have a closer look at them.

为了映射多对多的关联,我们使用@ManyToMany@JoinTable@JoinColumn注释。让我们仔细看一下它们。

The @ManyToMany annotation is used in both classes to create the many-to-many relationship between the entities.

@ManyToMany注解在两个类中都被用来创建实体之间的多对多关系。

This association has two sides i.e. the owning side and the inverse side. In our example, the owning side is Employee so the join table is specified on the owning side by using the @JoinTable annotation in Employee class. The @JoinTable is used to define the join/link table. In this case, it is Employee_Project.

这种关联有两个方面,即拥有方和反方。在我们的例子中,拥有方是Employee,所以连接表是通过使用@JoinTable注解在Employee类中指定拥有方。@JoinTable被用来定义连接/链接表。在本例中,它是Employee_Project。

The @JoinColumn annotation is used to specify the join/linking column with the main table. Here, the join column is employee_id and project_id is the inverse join column since Project is on the inverse side of the relationship.

@JoinColumn 注解被用来指定与主表的连接/链接列。这里,连接列是employee_idproject_id是反向连接列,因为Project在关系的反面。

In the Project class, the mappedBy attribute is used in the @ManyToMany annotation to indicate that the employees collection is mapped by the projects collection of the owner side.

项目类中,mappedBy属性被用于@ManyToMany注解以表明employees集合被所有者的projects集合映射。

5. Execution

5.执行

In order to see the many-to-many annotation in action, we can write the following JUnit test:

为了看到多对多注解的作用,我们可以编写以下JUnit测试。

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

	//...

	@Test
        public void givenSession_whenRead_thenReturnsMtoMdata() {
	    prepareData();
       	    @SuppressWarnings("unchecked")
	    List<Employee> employeeList = session.createQuery("FROM Employee").list();
            @SuppressWarnings("unchecked")
	    List<Project> projectList = session.createQuery("FROM Project").list();
            assertNotNull(employeeList);
            assertNotNull(projectList);
            assertEquals(2, employeeList.size());
            assertEquals(2, projectList.size());
        
            for(Employee employee : employeeList) {
               assertNotNull(employee.getProjects());
               assertEquals(2, employee.getProjects().size());
            }
            for(Project project : projectList) {
               assertNotNull(project.getEmployees());
               assertEquals(2, project.getEmployees().size());
            }
        }

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

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

	    for (String emp : employeeData) {
		Employee employee = new Employee(emp.split(" ")[0], emp.split(" ")[1]);
		employee.setProjects(projects);
			
	        for (Project proj : projects) {
		    proj.getEmployees().add(employee);
		}
			
		session.persist(employee);
	    }
	}
	
	//...
}

We can see the many-to-many relationship between the two entities created in the database: the employee, project, and employee_project tables with sample data representing the relationship.

我们可以看到在数据库中创建的两个实体之间的多对多关系:employeeprojectemployee_project表,其样本数据代表这种关系。

6. Conclusion

6.结论

In this tutorial, we saw how to create mappings using Hibernate’s many-to-many annotations, which is a more convenient counterpart compared to creating XML mapping files.

在本教程中,我们看到了如何使用Hibernate的多对多注解来创建映射,与创建XML映射文件相比,这是更方便的对应方法。

The source code of this tutorial can be found over on GitHub.

本教程的源代码可以在GitHub上找到over