Hibernate的实体关系映射包括一对多、多对一、多对多这三种类型。
一般前两种是组合使用,成为一个双向多对一映射。(上一篇文章中的情况)
而多对多则分两种情况:
1.多对多只是为了表明二者的联系,不包含其他属性。
2.多对多不只是表明二者联系,而且这个联系也有自身的属性。
如职工Employee和项目Project是多对多的关系。
对于第一种情况,可以直接使用Hibernate的<many-to-many>标签来进行配置,不需要自己建立中间表和对应实体。
Employee:
<span style="font-size:14px;"> private int employee_id;
private String employee_name;
private Set<Project> projects = new HashSet<Project>();</span>
Project:
<span style="font-size:14px;"> private int project_id;
private String project_name;
private Set<Employee> employees = new HashSet<Employee>();
</span>
Employee.hbm.xml:
<span style="font-size:14px;">
<class name = "Employee" table = "employee">
<id name = "employee_id" column = "employee_id">
<generator class = "assigned"/>
</id>
<property name = "employee_name" column = "employee_name"></property>
<set name = "projects" table = "pro_emp" cascade="save-update" inverse="true" >
<key column = "remployee_id"></key>
<many-to-many class = "Project" column="rproject_d"></many-to-many>
</set>
</class></span>
Project.hbm.xml:
<span style="font-size:14px;"> <class name="Project" table="project">
<id name="project_id" column="project_id">
<generator class="assigned" />
</id>
<property name="project_name" column="project_name"></property>
<set name="employees" table="pro_emp" cascade="save-update" lazy="false">
<key column="rproject_d"></key>
<many-to-many class="Employee" column="remployee_id"></many-to-many>
</set>
</class></span>
这样就实现了双方的多对多关联,运行后数据库中会生成一个中间表pro_emp,其中有两个属性:rproject和remployee,分别用来保存项目号与职工号。
查询的时候双方都可以查询另一方,如要查询职工号为1的职员工作的项目,可以这样查询:
<span style="font-size:14px;">String hql = "from employee where employee_id = 1";
Query query = session.createQuery(hql);
List list = query.list();
Employee e = (Employee)list.get(0);
Set projects = e.getProjects();
Iterator iter = projects.iterator();
while(iter.hasNext()){
Project p = (Project)iter.Next();
System.out.println(p.getProject_name());
}
</span>
而对于第二种情况则不能简单的使用多对多<many-to-many>标签来配置,而应该自己建立一个中间表及对应的实体,表的字段有双方的主键作为外键,以及联系自身具有的属性。双方分别与中间表建立多对一的联系。
这里同样有两种方式,一是采用联合主键,二是新建一个主键。我采用的是新建一个主键的方式:(假设联系表自身属性为加入项目的时间)
<span style="font-size:14px;">表pro_emp(id,project_id,employee_id,time)</span>
新建一个实体类Pro_Emp:
<span style="font-size:14px;">private int id;
private Project project;
private Employee employee;
private Date time;</span>
Employee:
<span style="font-size:14px;"> private int employee_id;
private String employee_name;
private Set<Pro_Emp> projects = new HashSet<Pro_Emp>();</span>
Project:
<span style="font-size:14px;"> private int project_id;
private String project_name;
private Set<Pro_Emp> employees = new HashSet<Pro_Emp>();
</span>
Pro_Emp.hbm.xml:
<span style="font-size:14px;"> <class name="Pro_Emp" table="pro_emp">
<id name="id" column="id">
<generator class="assigned" />
</id>
<many-to-one name = "project" class = "Project">
<column name = "project_id"></column>
</span><pre name="code" class="java"><span style="font-size:14px;"> <many-to-one>
</span><pre name="code" class="java"><span style="font-size:14px;"> <many-to-one name = "employee" class = "Employee">
<column name = "employee_id"></column>
</span><pre name="code" class="java"><span style="font-size:14px;"> <many-to-one></span>
</class>
Employee.hbm.xml:
<span style="font-size:14px;"> <class name = "Employee" table = "employee">
<id name = "employee_id" column = "employee_id">
<generator class = "assigned"/>
</id>
<property name = "employee_name" column = "employee_name"></property>
<set name = "projects" cascade="save-update" inverse="true" >
<key column = "employee_id"></key>
<one-to-many class = "Project" ></one-to-many>
</set>
</class></span>
Project.hbm.xml:
<span style="font-size:14px;"> </span><pre name="code" class="java"><span style="font-size:14px;"> <class name="Project" table="project">
<id name="project_id" column="project_id">
<generator class="assigned" />
</id>
<property name="project_name" column="project_name"></property>
<set name="employees" cascade="save-update" lazy="false">
<key column="project_d"></key>
<one-to-many class="Employee" ></one-to-many>
</set>
</class></span>
这样就配置好了Employee与Pro_Emp的多对一,以及Project与Pro_Emp的多对一联系。
在保存一个Pro_Emp联系元组的时候,可以取出一个项目元组和一个职工元组,使用set方法加入到pro_emp的属性中,然后调用session.save(pro_emp)方法将其持久化到数据库中。(具体代码与第一种情况类似,不再贴出来)
总结:大多数的多对多联系都具有自身的属性,这样的话就需要使用拆分的方式,将一个多对多联系拆分为两个多对一。拆分之后还有一个问题就是中间表的主键设置问题,是设置为联合主键还是新建一个主键,这里建议是新建一个主键,因为如果要采用联合主键的方式,在保存的时候只能按照参照主键来设置属性。不够方便。也可能是目前刚接触,对这块而不够了解,采用联合主键可能有其独特的作用,暂且不谈。