例:员工Employee分为正式工SalaryEmployee和临时工HourEmployee。子类表的字段都不能使用非空约束。
1)父类、子类在同一张表,表中有“辨别者列”。通过辨别者列值,区分父类数据和子类数据。
2)父类、子类各一张表。将公共数据放入父表,将个体数据存放子表,子表通过外键关联父表的公共数据。
3)父子类分别建表,父子表无关联,将父类数据存放到父类表,将子类数据存放子类表 ,父子表采用连续增长主键
父子类数据在同一张表,引入辨别者列(discriminator)用来区分数据记录是父类还是子类。
对于继承关系映射,不需要为每个类建立hbm文件。只需要针对父类编写hbm即可。
<hibernate-mapping package="cn.cvu.hibernate.domain"> <!-- 0.父类、子类都要配置辨别值,将在辨别者列中存储 --> <class name="PojoHuman" table="tb_human" select-before-update="true" discriminator-value="human"> <id name="id" column="t_id" type="int"> <generator class="native" /> </id> <!-- 1.首先配置辨别者列! column="自定义列名" type="自定义类型" --> <discriminator column="t_disc" type="string"/> <!-- 2.然后配置父类的通用属性! --> <property name="name" column="t_name" /> <!-- 3.最后配置子类关系 name="子类全路径" --> <subclass name="cn.cvu.hibernate.domain.PojoWoman" discriminator-value="woman"> <!-- 子类的个体属性 --> <property name="waistline"/> <property name="beauty"/> </subclass> <subclass name="cn.cvu.hibernate.domain.PojoMan" discriminator-value="man"> <property name="height"/> <property name="beauty"/> </subclass> </class> </hibernate-mapping>
(1)插入:
public void test(){ Session session = UtilGetSession.openSession(); Transaction transaction = session.beginTransaction(); PojoHuman human = new PojoHuman(); human.setName("地球人"); PojoWoman woman = new PojoWoman(); woman.setName("女人"); woman.setWaistline(36); woman.setBeauty("漂亮"); PojoMan man = new PojoMan(); man.setName("男人"); man.setHeight(175); man.setSpeed(12); session.save(human); session.save(woman); session.save(man); transaction.commit(); session.close(); }
(2)查询,通常使用HQL:
String hqlHuman="from PojoHuman"; Query queryHuman = session.createQuery(hqlHuman); List listHuman = queryHuman.list(); System.out.println(listHuman);
为每个父类和子类建立单独数据表,将公共数据放入父表, 将个体信息存入子表,子表通过外键与父表关联。
<hibernate-mapping package="cn.cvu.hibernate.domain"> <class name="PojoHuman" table="tb_human" select-before-update="true"> <id name="id" column="t_id" type="int"> <generator class="native" /> </id> <!-- 父类的通用属性 --> <property name="name" column="t_name" /> <!-- 子类配置 name="子类全路径" table="子类对应的表" --> <joined-subclass name="cn.cvu.hibernate.domain.PojoWoman" table="tb_woman"> <!-- 子表主键,也是关联父表的外键 --> <key column="t_human_child"></key> <!-- 子类的个体属性 --> <property name="waistline"></property> <property name="beauty"></property> </joined-subclass> <joined-subclass name="cn.cvu.hibernate.domain.PojoMan" table="tb_man"> <key column="t_human_child"></key> <property name="height"></property> <property name="speed"></property> </joined-subclass> </class> </hibernate-mapping>
(2)测试查询:
同上。
(3)测试删除:
PojoHuman human = new PojoHuman(); human.setId(2); //父类托管对象 session.delete(human);
org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
WARN: SQL Error: 1451, SQLState: 23000
org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
ERROR: Cannot delete or update a parent row: a foreign key constraint fails
(`db_hibernate`.`tb_woman`, CONSTRAINT `FK_8n9ux8k3f9lja8fldi8om7cg0` FOREIGN KEY
(`t_human_child`) REFERENCES `tb_human` (`t_id`))
父类和子类单独建表,父表和子表无关联;父类数据插入父表,子类数据插入子表,父表和子表的主键连续自增。
注意:不能使用identity、native,因为需要在多张表完成主键连续自增;可以使用sequence(mysql不支持)、 increment (hibernate实现,max(id)+1)。
<hibernate-mapping package="cn.cvu.hibernate.domain"> <class name="PojoHuman" table="tb_human" select-before-update="true"> <id name="id" column="t_id" type="int"> <generator class="increment" /> </id> <!-- 父类的通用属性 --> <property name="name" column="t_name" /> <!-- 子类配置 name="子类全路径" table="子类对应的表" --> <union-subclass name="cn.cvu.hibernate.domain.PojoMan" table="tb_man"> <!-- 子类属性 --> <property name="height"/> <property name="speed"/> </union-subclass> <union-subclass name="cn.cvu.hibernate.domain.PojoWoman" table="tb_woman"> <property name="waistline"/> <property name="beauty"/> </union-subclass> </class> </hibernate-mapping>
(1)测试保存:
(2)测试查询:
(3)查询删除:
如果父子类数据非常简单,可以使用subclass , 重点推荐joinedsubclass (性能最好),不推荐unionsubclass。
- end