常用的Hibernate的映射与数据库表的关系(二)
上篇文章介绍了下多对一的关系关联映射,这次来介绍下其他的几种映射。
首先,介绍下一对多。有人会有疑问:一对多和多对一不是一样的吗?下面我们接着用学生和班级的例子继续来说明下。一对多表示:控制方在一的这一端,比如可以查找属于同一个班级下的所有的学生。这个该怎么实现,试想下你要查找班级下的学生你的Classes类下面就必须要有Student类对象的这个属性字段。private Set<Student> students;利用这个属性来加载属于当前班级下的所有的学生。其他的属性字段同一对多的一样。项目结构图如下:
当前使用的是一对多的映射,配置一般在一的一端。配置如下:
注意下当前我们使用的不再是<property>而是<set>标签。set标签中name和property的name一样表示利用Classes这个类的students属性来生成一个字段,该字段名字由<key>来指定也就是cid,并且该字段为Student的外键(由<one-to-many>来指定)。
运行下,同样的会产生如下的代码:
drop table if exists t_classes
drop table if exists t_student
create table t_classes (cid integer not null auto_increment, cname varchar(50), primary key (cid))
create table t_student (sid integer not null auto_increment, sname varchar(50), cid integer, primary key (sid))
alter table t_student add index FK4B907570D95D9B22 (cid), add constraint FK4B907570D95D9B22 foreign key (cid) references t_classes (cid)
配置的这个地方有两点值得我们注意:试想下,在一对多的关系下我们首先加载的是一的这一方,然后是多的那一方,所以代码可以是:
上面的代码我们是直接保存Classes对象的,直接运行的话会产生异常:org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.fendou.hibernate.Student。原因是Student在未保存之前是一个瞬时对象,无法被持久化。有两种解决办法第一:先保存Student再保存Classes(把注释去掉),第二:在刚刚的Classes.hbm.xml配置中保留cascade="all"。
第二点值得我们注意的地方是:假设我们的属性字段允许为空,即Student.hbm.xml修改成<property name="name" length="50" column="sname" not-null="true"/>再把Classes.hbm.xml的配置:<set name="students" cascade="all" inverse="true">
去掉cascade="all" inverse="true"同样会报异常。因为我们先加载的是Classes对象,Hibernate只知道有一个Student对象,但对于他的数据约束信息一无所知,加载Student对象的时候并不知道字段可以为空,这样就会违反约束条件。
对于一对多的关联映射,我们一般会修改成双向关联,既可以从多的一端加载也可以从一的一端加载,方便操作。这样的话只需要在多的一端修改配置文件Student.hbm.xml。增加如下配置:<many-to-one name="classes" column="cid"/>注意字段名cid应该和一端的那边一致。
再介绍下:多对多关联关系映射。利用学生与课程之间的关系来解释,一个学生可以选择多门课程,一门课程可以被多个学生选。由于多对多的映射一般也会采用双向关联,所以只介绍双向关联的配置。如果我们用SQL语句来写的话,只需要建立第三张表,然后加入一个联合主键就可以,同理在Hibernate中也一样。现在我们的Student类有private int id;private String name;private Set<Course> courses;三个字段。Course类也有三个字段private int id;private String name;private Set<Student> students;项目结构如图:
Student.hbm.xml和Course.hbm.xml配置如下图:
介绍下配置:多对多的映射:产生第三张表用来联系前两张表,且有联合主键
<set name="courses" table="sc">
<key column="sid" />
<many-to-many column="cid" class="Course" />
</set>
table表示含有联合主键的第三张表,key表示外键,<many-to-many>中的column表表示另外的一个外键,
class表示另外的一张表。
运行生成的代码如下:
drop table if exists sc
drop table if exists t_course
drop table if exists t_student
create table sc (sid integer not null, cid integer not null, primary key (cid, sid))
create table t_course (cid integer not null auto_increment, cname varchar(50), primary key (cid))
create table t_student (sid integer not null auto_increment, sname varchar(50), primary key (sid))
alter table sc add index FKE50367B2147 (sid), add constraint FKE50367B2147 foreign key (sid) references t_student (sid)
alter table sc add index FKE50BCE53EDB (cid), add constraint FKE50BCE53EDB foreign key (cid) references t_course (cid)
(未完待续,下次介绍继承映射)