本文简单讲述hibernate的Many2One、One2Many和Many2Many的单双向映射的annotation和xml的实现方式。
1.首先,先看下annotation的API文档
2.2.5.2. 多对一(Many-to-one)
在实体属性一级使用@ManyToOne注解来定义多对一关联:
@Entity() public class Flight implements Serializable { @ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE} ) @JoinColumn(name="COMP_ID") public Company getCompany() { return company; } ... }
其中@JoinColumn是可选的,关联字段默认值和一对一 (one to one)关联的情况相似, 列名为:主体的关联属性名+下划线+被关联端的主键列名. 在这个例子中是company_id,
因为关联的属性是company, Company的主键是id.
@ManyToOne注解有一个名为targetEntity的参数,
该参数定义了目标实体名.通常不需要定义该参数, 因为在大部分情况下默认值(表示关联关系的属性类型)就可以很好的满足要求了. 不过下面这种情况下这个参数就显得有意义了:使用接口作为返回值而不是常见的实体.
@Entity() public class Flight implements Serializable { @ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE}, targetEntity=CompanyImpl.class ) @JoinColumn(name="COMP_ID") public Company getCompany() { return company; } ... } public interface Company { ...
对于多对一也可以通过关联表的方式来映射。 通过@JoinTable注解可定义关联表, 该关联表包含了指回实体表的外键(通过@JoinTable.joinColumns)
以及指向目标实体表的外键(通过@JoinTable.inverseJoinColumns).
@Entity() public class Flight implements Serializable { @ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE} ) @JoinTable(name="Flight_Company", joinColumns = @JoinColumn(name="FLIGHT_ID"), inverseJoinColumns = @JoinColumn(name="COMP_ID") ) public Company getCompany() { return company; } ... }
2.2.5.3.2. 一对多(One-to-many)
在属性级使用 @OneToMany注解可定义一对多关联.一对多关联可以是双向关联.
2.2.5.3.2.1. 双向(Bidirectional)
在EJB3规范中多对一这端几乎总是双向关联中的主体(owner)端, 而一对多这端的关联注解为@OneToMany( mappedBy=... )
@Entity public class Troop { @OneToMany(mappedBy="troop") public Set<Soldier> getSoldiers() { ... } @Entity public class Soldier { @ManyToOne @JoinColumn(name="troop_fk") public Troop getTroop() { ... }
Troop 通过troop 属性和Soldier建立了一对多的双向关联.
在mappedBy端不必也不能再定义任何物理映射
对于一对多的双向映射,如果要一对多这一端维护关联关系, 你需要删除mappedBy元素并将多对一这端的 @JoinColumn的insertable和updatable设置为false.
很明显,这种方案不会得到什么明显的优化,而且还会增加一些附加的UPDATE语句.
@Entity public class Troop { @OneToMany @JoinColumn(name="troop_fk") //we need to duplicate the physical information public Set<Soldier> getSoldiers() { ... } @Entity public class Soldier { @ManyToOne @JoinColumn(name="troop_fk", insertable=false, updatable=false) public Troop getTroop() { ... }
2.2.5.3.2.2. 单向(Unidirectional)
通过在被拥有的实体端(owned entity)增加一个外键列来实现一对多单向关联是很少见的,也是不推荐的. 我们强烈建议通过一个联接表(join table)来实现这种关联(下一节会对此进行解释). 可以通过@JoinColumn注解来描述这种单向关联关系.
@Entity public class Customer implements Serializable { @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER) @JoinColumn(name="CUST_ID") public Set<Ticket> getTickets() { ... } @Entity public class Ticket implements Serializable { ... //no bidir }
Customer 通过 CUST_ID列和Ticket 建立了单向关联关系.
2.2.5.3.2.3. 通过关联表处理单向关联
通过联接表处理单向一对多关联是首选方式.这种关联通过@JoinTable注解来进行描述.
@Entity public class Trainer { @OneToMany @JoinTable( name="TrainedMonkeys", joinColumns = @JoinColumn( name="trainer_id"), inverseJoinColumns = @JoinColumn( name="monkey_id") ) public Set<Monkey> getTrainedMonkeys() { ... } @Entity public class Monkey { ... //no bidir }
上面这个例子中,Trainer通过 TrainedMonkeys表和 Monkey 建立了单向关联.
其中外键trainer_id关联到Trainer (joinColumns),
而外键monkey_id关联到 Monkey (inversejoinColumns).
2.2.5.3.2.4. 默认处理机制
通过联接表来建立单向一对多关联不需要描述任何物理映射. 表名由以下三个部分组成:主表(owner table)表名+下划线+从表(the other side table)表名. 指向主表的外键名:主表表名+下划线+主表主键列名 指向从表的外键名:主表所对应实体的属性名+下划线+从表主键列名 指向从表的外键定义为唯一约束,用来表示一对多的关联关系.
@Entity public class Trainer { @OneToMany public Set<Tiger> getTrainedTigers() { ... } @Entity public class Tiger { ... //no bidir }
上面这个例子中,Trainer和Tiger 通过联接表 Trainer_Tiger建立单向关联关系,
其中外键trainer_id关联到Trainer (主表表名, _(下划线),
trainer id), 而外键trainedTigers_id关联到Tiger (属性名称, _(下划线),
Tiger表的主键列名).
2.2.5.3.3. 多对多(Many-to-many)
2.2.5.3.3.1. 定义
你可以通过@ManyToMany注解可定义的多对多关联. 同时,你也需要通过注解@JoinTable描述关联表和关联条件. 如果是双向关联,其中一段必须定义为owner,另一端必须定义为inverse(在对关联表进行更新操作时这一端将被忽略):
@Entity public class Employer implements Serializable { @ManyToMany( targetEntity=org.hibernate.test.metadata.manytomany.Employee.class, cascade={CascadeType.PERSIST, CascadeType.MERGE} ) @JoinTable( name="EMPLOYER_EMPLOYEE", [email protected](name="EMPER_ID"), [email protected](name="EMPEE_ID") ) public Collection getEmployees() { return employees; } ... }
@Entity public class Employee implements Serializable { @ManyToMany( cascade = {CascadeType.PERSIST, CascadeType.MERGE}, mappedBy = "employees", targetEntity = Employer.class ) public Collection getEmployers() { return employers; } }
至此,我们已经展示了很多跟关联有关的声明定义以及属性细节. 下面我们将深入介绍@JoinTable注解,该注解定义了联接表的表名, 联接列数组(注解中定义数组的格式为{ A, B, C }), 以及inverse联接列数组. 后者是关联表中关联到Employee主键的列(the
"other side").
正如前面所示,被关联端不必也不能描述物理映射: 只需要一个简单的mappedBy参数,该参数包含了主体端的属性名,这样就绑定双方的关系.
2.2.5.3.3.2. 默认值
和其他许多注解一样,在多对多关联中很多值是自动生成. 当双向多对多关联中没有定义任何物理映射时,Hibernate根据以下规则生成相应的值. 关联表名:主表表名+_下划线+从表表名, 关联到主表的外键名:主表名+_下划线+主表中的主键列名. 关联到从表的外键名:主表中用于关联的属性名+_下划线+从表的主键列名.
以上规则对于双向一对多关联同样有效.
@Entity public class Store { @ManyToMany(cascade = CascadeType.PERSIST) public Set<City> getImplantedIn() { ... } } @Entity public class City { ... //no bidirectional relationship }
上面这个例子中,Store_Table作为联接表. Store_id列是联接到Store表的外键.
而implantedIn_id列则联接到City表.
当双向多对多关联中没有定义任何物理映射时, Hibernate根据以下规则生成相应的值 关联表名: :主表表名+_下划线+从表表名, 关联到主表的外键名:从表用于关联的属性名+_下划线+主表中的主键列名. 关联到从表的外键名:主表用于关联的属性名+_下划线+从表的主键列名.
以上规则对于双向一对多关联同样有效.
@Entity public class Store { @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}) public Set<Customer> getCustomers() { ... } } @Entity public class Customer { @ManyToMany(mappedBy="customers") public Set<Store> getStores() { ... } }
在上面这个例子中,Store_Customer作为联接表. stores_id列是联接到Store表的外键,
而customers_id列联接到City表.
2.再来看下xml的API文档
7.2. 单向关联(Unidirectional associations)
7.2.1. Many-to-one
<class name="Person"> <id name="id" column="personId"> <generator class="native"/> </id> <many-to-one name="address" column="addressId" not-null="true"/> </class> <class name="Address"> <id name="id" column="addressId"> <generator class="native"/> </id> </class>
create table Person ( personId bigint not null primary key, addressId bigint not null ) create table Address ( addressId bigint not null primary key )
7.2.3. One-to-many
<class name="Person"> <id name="id" column="personId"> <generator class="native"/> </id> <set name="addresses"> <key column="personId" not-null="true"/> <one-to-many class="Address"/> </set> </class> <class name="Address"> <id name="id" column="addressId"> <generator class="native"/> </id> </class>
create table Person ( personId bigint not null primary key ) create table Address ( addressId bigint not null primary key, personId bigint not null )
You should instead use a join table for this kind of association.
7.3. 使用连接表的单向关联(Unidirectional associations with join tables)
7.3.1. One-to-many
<class name="Person"> <id name="id" column="personId"> <generator class="native"/> </id> <set name="addresses" table="PersonAddress"> <key column="personId"/> <many-to-many column="addressId" unique="true" class="Address"/> </set> </class> <class name="Address"> <id name="id" column="addressId"> <generator class="native"/> </id> </class>
create table Person ( personId bigint not null primary key ) create table PersonAddress ( personId not null, addressId bigint not null primary key ) create table Address ( addressId bigint not null primary key )
7.3.2. Many-to-one
<class name="Person"> <id name="id" column="personId"> <generator class="native"/> </id> <join table="PersonAddress" optional="true"> <key column="personId" unique="true"/> <many-to-one name="address" column="addressId" not-null="true"/> </join> </class> <class name="Address"> <id name="id" column="addressId"> <generator class="native"/> </id> </class>
create table Person ( personId bigint not null primary key ) create table PersonAddress ( personId bigint not null primary key, addressId bigint not null ) create table Address ( addressId bigint not null primary key )
7.3.4. Many-to-many
Finally, here is an example of a unidirectional many-to-many association.
<class name="Person"> <id name="id" column="personId"> <generator class="native"/> </id> <set name="addresses" table="PersonAddress"> <key column="personId"/> <many-to-many column="addressId" class="Address"/> </set> </class> <class name="Address"> <id name="id" column="addressId"> <generator class="native"/> </id> </class>
create table Person ( personId bigint not null primary key ) create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) ) create table Address ( addressId bigint not null primary key )
7.4. 双向关联(Bidirectional associations)
7.4.1. one-to-many / many-to-one
<class name="Person"> <id name="id" column="personId"> <generator class="native"/> </id> <many-to-one name="address" column="addressId" not-null="true"/> </class> <class name="Address"> <id name="id" column="addressId"> <generator class="native"/> </id> <set name="people" inverse="true"> <key column="addressId"/> <one-to-many class="Person"/> </set> </class>
create table Person ( personId bigint not null primary key, addressId bigint not null ) create table Address ( addressId bigint not null primary key )
<class name="Person"> <id name="id"/> ... <many-to-one name="address" column="addressId" not-null="true" insert="false" update="false"/> </class> <class name="Address"> <id name="id"/> ... <list name="people"> <key column="addressId" not-null="true"/> <list-index column="peopleIdx"/> <one-to-many class="Person"/> </list> </class>
7.5. 使用连接表的双向关联(Bidirectional associations with join tables)
7.5.1. one-to-many / many-to-one
<class name="Person"> <id name="id" column="personId"> <generator class="native"/> </id> <set name="addresses" table="PersonAddress"> <key column="personId"/> <many-to-many column="addressId" unique="true" class="Address"/> </set> </class> <class name="Address"> <id name="id" column="addressId"> <generator class="native"/> </id> <join table="PersonAddress" inverse="true" optional="true"> <key column="addressId"/> <many-to-one name="person" column="personId" not-null="true"/> </join> </class>
create table Person ( personId bigint not null primary key ) create table PersonAddress ( personId bigint not null, addressId bigint not null primary key ) create table Address ( addressId bigint not null primary key )
7.5.3. Many-to-many
Here is an example of a bidirectional many-to-many association.
<class name="Person"> <id name="id" column="personId"> <generator class="native"/> </id> <set name="addresses" table="PersonAddress"> <key column="personId"/> <many-to-many column="addressId" class="Address"/> </set> </class> <class name="Address"> <id name="id" column="addressId"> <generator class="native"/> </id> <set name="people" inverse="true" table="PersonAddress"> <key column="addressId"/> <many-to-many column="personId" class="Person"/> </set> </class>
create table Person ( personId bigint not null primary key ) create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) ) create table Address ( addressId bigint not null primary key )
3.Many2One单向映射的annotation版本
使用Group和User,二者为多对一的关系,即一个Group有多个User,多个User对应一个Group
需要在User中引用Group,并在getGroup使用@ManyToOne
Group
package com.baosight.model; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name="t_group") public class Group { private String id; private String name; @Id @GeneratedValue//auto public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
User
package com.baosight.model; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.ManyToOne; import javax.persistence.Table; @Entity @Table(name="t_user") public class User { private String id; private String name; private Group group ; @Id @GeneratedValue//auto public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @ManyToOne public Group getGroup() { return group; } public void setGroup(Group group) { this.group = group; } }
使用JUnit进行测试,OrMappingTest.java,注意此类在之后的测试中通用
package com.baosight.model; import org.hibernate.SessionFactory; import org.hibernate.cfg.AnnotationConfiguration; import org.hibernate.cfg.Configuration; import org.hibernate.tool.hbm2ddl.SchemaExport; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; public class OrMappingTest { private static SessionFactory sf = null; @BeforeClass public static void beforeClass(){ // 读取配置文件 Configuration cfg = new AnnotationConfiguration(); // 得到session工厂 sf = cfg.configure().buildSessionFactory(); } @Test public void testSchemaExport() { new SchemaExport(new AnnotationConfiguration().configure()).create(false, true); } @AfterClass public static void afterClass(){ // 关闭session工厂 sf.close(); } }
测试结果为:
4.Many2One单向映射的xml版本
使用School和Student,二者为多对一的关系,即一个School有多个Student,多个Student对应一个School
需要在Student中引用School,并在Student.hbm.xml使用<many-to-one name="school" column="schoolId"></many-to-one>
School
package com.baosight.model; public class School { private String id; private String name; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
Student
package com.baosight.model; public class Student { private String id; private String num; private School school; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getNum() { return num; } public void setNum(String num) { this.num = num; } public School getSchool() { return school; } public void setSchool(School school) { this.school = school; } }
School.hbm.xml
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.baosight.model"> <class name="School" dynamic-update="true"> <id name="id" > <generator class="native"></generator> </id> <property name="name"></property> </class> </hibernate-mapping>
Student.hbm.xml
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.baosight.model"> <class name="Student" dynamic-update="true"> <id name="id" > <generator class="native"></generator> </id> <property name="num"></property> <many-to-one name="school" column="schoolId"></many-to-one> </class> </hibernate-mapping>
测试结果为:
5.One2Many单向映射的annotation版本
使用Group和User,二者为一对多的关系,即一个Group有多个User,多个User对应一个Group
需要在Group中引用User的集合Set<User> users,并在getUsers使用@OneToMany
@JoinColumn(name="groupId")
Group
package com.baosight.model; import java.util.Set; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.OneToMany; import javax.persistence.Table; @Entity @Table(name="t_group") public class Group { private String id; private String name; private Set<User> users; @Id @GeneratedValue//auto public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @OneToMany @JoinColumn(name="groupId") public Set<User> getUsers() { return users; } public void setUsers(Set<User> users) { this.users = users; } }
User
package com.baosight.model; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; import javax.persistence.OneToOne; import javax.persistence.Table; @Entity @Table(name="t_user") public class User { private String id; private String name; @Id @GeneratedValue//auto public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
测试结果为:
6.One2Many单向映射的xml版本
使用School和Student,二者为一对多的关系,即一个School有多个Student,多个Student对应一个School
需要在School中引用Student的集合Set<Student> students,并在School.hbm.xml使用<set name="students">
<key column="schoolId"/>
<one-to-many class="Student"/>
</set>
School
package com.baosight.model; import java.util.Set; public class School { private String id; private String name; private Set<Student> students; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set<Student> getStudents() { return students; } public void setStudents(Set<Student> students) { this.students = students; } }
Student
package com.baosight.model; public class Student { private String id; private String num; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getNum() { return num; } public void setNum(String num) { this.num = num; } }
School.hbm.xml
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.baosight.model"> <class name="School" dynamic-update="true"> <id name="id" > <generator class="native"></generator> </id> <property name="name"></property> <set name="students"> <key column="schoolId"/> <one-to-many class="Student"/> </set> </class> </hibernate-mapping>
Student.hbm.xml
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.baosight.model"> <class name="Student" dynamic-update="true"> <id name="id" > <generator class="native"></generator> </id> <property name="num"></property> </class> </hibernate-mapping>
测试结果为:
7.Many2One/One2Many双向映射的annotation版本
使用Group和User,二者为多对一的关系,即一个Group有多个User,多个User对应一个Group
需要在User中引用Group,并在getGroup使用@ManyToOne
还需要在Group中引用User的集合Set<User> users,并在getUsers使用@OneToMany(mappedBy="group"),mappedBy表示映射关系由User中的group来维持
Group
package com.baosight.model; import java.util.Set; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.OneToMany; import javax.persistence.Table; @Entity @Table(name="t_group") public class Group { private String id; private String name; private Set<User> users; @Id @GeneratedValue//auto public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @OneToMany(mappedBy="group") public Set<User> getUsers() { return users; } public void setUsers(Set<User> users) { this.users = users; } }
User
package com.baosight.model; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; import javax.persistence.OneToOne; import javax.persistence.Table; @Entity @Table(name="t_user") public class User { private String id; private String name; private Group group; @Id @GeneratedValue//auto public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @ManyToOne public Group getGroup() { return group; } public void setGroup(Group group) { this.group = group; } }
测试结果为:
8.Many2One/One2Many双向映射的xml版本
使用School和Student,二者为多对一的关系,即一个School有多个Student,多个Student对应一个School
需要在Student中引用School,并在Student.hbm.xml使用<many-to-one name="school" column="schoolId"></many-to-one>
还需要需要在School中引用Student的集合Set<Student> students,并在School.hbm.xml使用<set name="students">
<key column="schoolId"/>
<one-to-many class="Student"/>
</set>
School
package com.baosight.model; import java.util.Set; public class School { private String id; private String name; private Set<Student> students; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set<Student> getStudents() { return students; } public void setStudents(Set<Student> students) { this.students = students; } }
Student
package com.baosight.model; public class Student { private String id; private String num; private School school; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getNum() { return num; } public void setNum(String num) { this.num = num; } public School getSchool() { return school; } public void setSchool(School school) { this.school = school; } }
School.hbm.xml
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.baosight.model"> <class name="School" dynamic-update="true"> <id name="id" > <generator class="native"></generator> </id> <property name="name"></property> <set name="students"> <key column="schoolId"/> <one-to-many class="Student"/> </set> </class> </hibernate-mapping>
Student.hbm.xml
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.baosight.model"> <class name="Student" dynamic-update="true"> <id name="id" > <generator class="native"></generator> </id> <property name="num"></property> <many-to-one name="school" column="schoolId"></many-to-one> </class> </hibernate-mapping>
测试结果:
9.Many2Many单向映射的annotation版本
使用Teacher和Student,二者为多对多的关系,即一个Teacher有多个Student,一个Student对应多个Teacher
本例单向的意思是Teacher引用Student的集合Set<Student> students,并在getStudents使用@ManyToMany
@JoinTable(name="t_s",
joinColumns={@JoinColumn(name="teacher_id")},
inverseJoinColumns={@JoinColumn(name="student_id")}
)
Teacher
package com.baosight.model; import java.util.Set; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinColumns; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; import javax.persistence.OneToMany; import javax.persistence.Table; @Entity public class Teacher { private String id; private String name; private Set<Student> students; @Id @GeneratedValue//auto public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @ManyToMany @JoinTable(name="t_s", joinColumns={@JoinColumn(name="teacher_id")}, inverseJoinColumns={@JoinColumn(name="student_id")} ) public Set<Student> getStudents() { return students; } public void setStudents(Set<Student> students) { this.students = students; } }
Student
package com.baosight.model; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; import javax.persistence.OneToOne; import javax.persistence.Table; @Entity public class Student { private String id; private String name; @Id @GeneratedValue//auto public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
测试结果为:
10.Many2Many单向映射的xml版本
使用Order和Product,二者为多对多的关系,即一个Order有多个Product,一个Product对应多个Order
本例单向的意思是需要在Order中引用Product的集合Set<Product> products,并在Order.hbm.xml使用
<set name="products" table="order_pro">
<key column="orderId"/>
<many-to-many class="Product" column="productId"/>
</set>
Order
package com.baosight.model; import java.util.Set; public class Order { private String id; private String name; private Set<Product> products; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set<Product> getProducts() { return products; } public void setProducts(Set<Product> products) { this.products = products; } }
Product
package com.baosight.model; public class Product { private String id; private String num; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getNum() { return num; } public void setNum(String num) { this.num = num; } }
Order.hbm.xml
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.baosight.model"> <class name="Order" table="t_order" dynamic-update="true"> <id name="id" > <generator class="native"></generator> </id> <property name="name"></property> <set name="products" table="order_pro"> <key column="orderId"/> <many-to-many class="Product" column="productId"/> </set> </class> </hibernate-mapping>
Product.hbm.xml
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.baosight.model"> <class name="Product" table="t_product" dynamic-update="true"> <id name="id" > <generator class="native"></generator> </id> <property name="num"></property> </class> </hibernate-mapping>
测试结果为:
11.Many2Many双向映射的annotation版本
使用Teacher和Student,二者为多对多的关系,即一个Teacher有多个Student,一个Student对应多个Teacher
需要在Teacher引用Student的集合Set<Student> students,并在getStudents使用@ManyToMany
@JoinTable(name="t_s",
joinColumns={@JoinColumn(name="teacher_id")},
inverseJoinColumns={@JoinColumn(name="student_id")}
)
还需要在在Student引用Teacher的集合Set<Teacher> teachers,并在getTeachers使用@ManyToMany(mappedBy="students"),其中mappedBy表示映射关系由Teacher中的students来管理
Teacher
package com.baosight.model; import java.util.Set; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinColumns; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; import javax.persistence.OneToMany; import javax.persistence.Table; @Entity public class Teacher { private String id; private String name; private Set<Student> students; @Id @GeneratedValue//auto public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @ManyToMany @JoinTable(name="t_s", joinColumns={@JoinColumn(name="teacher_id")}, inverseJoinColumns={@JoinColumn(name="student_id")} ) public Set<Student> getStudents() { return students; } public void setStudents(Set<Student> students) { this.students = students; } }
Student
package com.baosight.model; import java.util.Set; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToMany; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; import javax.persistence.OneToOne; import javax.persistence.Table; @Entity public class Student { private String id; private String name; private Set<Teacher> teachers; @Id @GeneratedValue//auto public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @ManyToMany(mappedBy="students") public Set<Teacher> getTeachers() { return teachers; } public void setTeachers(Set<Teacher> teachers) { this.teachers = teachers; } }
测试结果为:
12.Many2Many双向映射的xml版本
使用Order和Product,二者为多对多的关系,即一个Order有多个Product,一个Product对应多个Order
需要在Order中引用Product的集合Set<Product> products,并在Order.hbm.xml使用
<set name="products" table="order_pro">
<key column="orderId"/>
<many-to-many class="Product" column="productId"/>
</set>
还需要在
需要在Product中引用Order的集合Set<Order> orders,并在Product.hbm.xml使用
<set name="orders" table="order_pro">
<key column="productId"/>
<many-to-many class="Order" column="orderId"/>
</set>
Order
package com.baosight.model; import java.util.Set; public class Order { private String id; private String name; private Set<Product> products; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set<Product> getProducts() { return products; } public void setProducts(Set<Product> products) { this.products = products; } }
Product
package com.baosight.model; import java.util.Set; public class Product { private String id; private String num; private Set<Order> orders; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getNum() { return num; } public void setNum(String num) { this.num = num; } public Set<Order> getOrders() { return orders; } public void setOrders(Set<Order> orders) { this.orders = orders; } }
Order.hbm.xml
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.baosight.model"> <class name="Order" table="t_order" dynamic-update="true"> <id name="id" > <generator class="native"></generator> </id> <property name="name"></property> <set name="products" table="order_pro"> <key column="orderId"/> <many-to-many class="Product" column="productId"/> </set> </class> </hibernate-mapping>
Product.hbm.xml
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.baosight.model"> <class name="Product" table="t_product" dynamic-update="true"> <id name="id" > <generator class="native"></generator> </id> <property name="num"></property> <set name="orders" table="order_pro"> <key column="productId"/> <many-to-many class="Order" column="orderId"/> </set> </class> </hibernate-mapping>
测试结果:
以上即为hibernate的Many2One/One2Many/Many2Many的内容,值得一提的是在实际的使用中多使用Many2One/One2Many,而Many2Many使用的不多。总之,这些映射关系需要在实际的使用中仔细体会。