- 一般的设计中,多对多关联映射,需要一个中间表
- Hibernate会自动生成中间表
- Hibernate使用many-to-many标签来表示多对多的关联
- 多对多的关联映射,在实体类中,跟一对多一样,也是用集合来表示的。
实例场景:
用户与他的角色(一个用户拥有多个角色,一个角色还可以属于多个用户)
Role实体类:
public class Role { private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } } |
User实体类:
public class User { private int id; private String name; private Set roles;//Role对象的集合 public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set getRoles() { return roles; } public void setRoles(Set roles) { this.roles = roles; } } |
Role映射文件:
<hibernate-mapping> <class name="com.wjt276.hibernate.Role" table="t_role"> <id name="id"> <generator class="native"/> </id> <property name="name" column="name"/> </class> </hibernate-mapping> |
User映射文件:
<hibernate-mapping> <class name="com.wjt276.hibernate.User" table="t_user"> <id name="id" column="id"> <generator class="native"/> </id> <property name="name"/> <!--使用<set>标签映射集合(set),标签中的name值为对象属性名(集合roles),而使用table属性是用于生成第三方表名称,例:table="t_user_role",但是第三方面中的字段是自动加入的,作为外键分别指向其它表。 所以表<key>标签设置,例:<key column="userid"/>,意思是:在第三方表(t_user_role)中加入一个外键并且指向当前的映射实体类所对应的表(t_user).使用<many-to-many>来指定此映射集合所对象的类(实例类),并且使用column属性加入一个外键指向Role实体类所对应的表(t_role) --> <set name="roles" table="t_user_role"> <key column="userid"/> <many-to-many class="com.wjt276.hibernate.Role" column="roleid"/> </set> </class> </hibernate-mapping> |
导出至数据库表所生成SQL语句
create table t_role (id integer not null auto_increment, name varchar(255), primary key (id)) create table t_user (id integer not null auto_increment, name varchar(255), primary key (id)) create table t_user_role (userid integer not null, roleid integer not null, primary key (userid, roleid)) alter table t_user_role add index FK331DEE5F1FB4B2D4 (roleid), add constraint FK331DEE5F1FB4B2D4 foreign key (roleid) references t_role (id) alter table t_user_role add index FK331DEE5F250A083E (userid), add constraint FK331DEE5F250A083E foreign key (userid) references t_user (id) |
注:根据DDL语句可以看出第三方表的主键是一个复合主键(primary key (userid, roleid)),也就是说记录不可以有相同的数据。
数据库表及结构:
多对多关联映射 单向数据存储:
session = HibernateUtils.getSession(); tx = session.beginTransaction(); Role r1 = new Role(); r1.setName("数据录入人员"); session.save(r1); Role r2 = new Role(); r2.setName("商务主管"); session.save(r2); Role r3 = new Role(); r3.setName("大区经理"); session.save(r3); User u1 = new User(); u1.setName("10"); Set<Role> u1Roles = new HashSet<Role>(); u1Roles.add(r1); u1Roles.add(r2); u1.setRoles(u1Roles); User u2 = new User(); u2.setName("祖儿"); Set<Role> u2Roles = new HashSet<Role>(); u2Roles.add(r2); u2Roles.add(r3); u2.setRoles(u2Roles); User u3 = new User(); u3.setName("成龙"); Set<Role> u3Roles = new HashSet<Role>(); u3Roles.add(r1); u3Roles.add(r2); u3Roles.add(r3); u3.setRoles(u3Roles); session.save(u1); session.save(u2); session.save(u3); tx.commit(); |
发出SQL语句:
Hibernate: insert into t_role (name) values (?) Hibernate: insert into t_role (name) values (?) Hibernate: insert into t_role (name) values (?) Hibernate: insert into t_user (name) values (?) Hibernate: insert into t_user (name) values (?) Hibernate: insert into t_user (name) values (?) Hibernate: insert into t_user_role (userid, roleid) values (?, ?) Hibernate: insert into t_user_role (userid, roleid) values (?, ?) Hibernate: insert into t_user_role (userid, roleid) values (?, ?) Hibernate: insert into t_user_role (userid, roleid) values (?, ?) Hibernate: insert into t_user_role (userid, roleid) values (?, ?) Hibernate: insert into t_user_role (userid, roleid) values (?, ?) Hibernate: insert into t_user_role (userid, roleid) values (?, ?) |
注:前三条SQL语句,添加Role记录,第三条到第六条添加User,最后7条SQL语句是在向第三方表(t_user_role)中添加多对多关系(User与Role关系)
多对多关联映射 单向数据加载:
session = HibernateUtils.getSession(); tx = session.beginTransaction(); User user = (User)session.load(User.class, 1); System.out.println("user.name=" + user.getName()); for (Iterator<Role> iter = user.getRoles().iterator(); iter.hasNext();){ Role role = (Role) iter.next(); System.out.println(role.getName()); } //提交事务 tx.commit(); |
Hibernate: select user0_.id as id0_0_, user0_.name as name0_0_ from t_user user0_ where user0_.id=? user.name=10 Hibernate: select roles0_.userid as userid1_, roles0_.roleid as roleid1_, role1_.id as id2_0_, role1_.name as name2_0_ from t_user_role roles0_ left outer join t_role role1_ on roles0_.roleid=role1_.id where roles0_.userid=? 商务主管 数据录入人员 |