Hibernate继承映射-多态关联

把类之间的继承关系反应到数据库中,三种方法

(1).只用一个表,子类的属性对应数据库表中额外的字段。使用<discriminator>和<subclass>

以下例子中Delivery(投递)类的两个子类PostDelivery(邮递)和ExpressDelivery(快递),注意必须在父类中也加上discrminator-value否则报“Could not format discriminator value to SQL string...”错。注意<discriminator>在除id以外的其他子元素之前,否则解析xml文件出错。

 1 <class name="com.tazi.domin.Delivery" table="DELIVERY" discriminator-value="2">
2 <id name="id" type="java.lang.Integer">
3 <column name="ID"/>
4 <generator class="identity"/>
5 </id>
6 <discriminator column="delivery_type" type="int"></discriminator>
7 <property name="phone" type="string" column="phone"/>
8 <property name="address" type="string" column="address"/>
9 <property name="postcode" type="string" column="POSTCODE"/>
10 <subclass name="com.tazi.domin.PostDelivery" discriminator-value="0">
11 <property name="parcelNumber" column="PARCEL_NUMBER"></property>
12 </subclass>
13 <subclass name="com.tazi.domin.ExpressDelivery" discriminator-value="1">
14 <property name="expressCompany" column="EXPRESS_COMPANY"></property>
15 <property name="expressNumber" column="EXPRESS_NUMBER"></property>
16 </subclass>
17 </class>

适用于在继承映射中总是需要多态查询,而且子类的属性相对比较少

(2).每一个具体类一个表

设置类Delivery为abstract在父类的class标签中也加上abstract="true",主键策略不能再使用identity,可以用increment或hilo.

 1     <class name="com.tazi.domin.Delivery" abstract="true">
2 <id name="id" type="java.lang.Integer">
3 <column name="ID"/>
4 <generator class="increment"/>
5 </id>
6 <property name="phone" type="string" column="phone"/>
7 <property name="address" type="string" column="address"/>
8 <property name="postcode" type="string" column="POSTCODE"/>
9 <union-subclass name="com.tazi.domin.PostDelivery" table="POST_DELIVERY">
10 <property name="parcelNumber" column="PARCEL_NUMBER"></property>
11 </union-subclass>
12 <union-subclass name="com.tazi.domin.ExpressDelivery" table="EXPRESS_DELIVERY">
13 <property name="expressCompany" column="EXPRESS_COMPANY"></property>
14 <property name="expressNumber" column="EXPRESS_NUMBER"></property>
15 </union-subclass>
16 </class>

例子1:单个子类的操作

1         PostDelivery pDelivery=new PostDelivery();
2 pDelivery.setPhone("13526356485");
3 pDelivery.setAddress("北京西街15号");
4 pDelivery.setPostcode("100080");
5 pDelivery.setParcelNumber("8578");
6 session.save(pDelivery);

hql输出,它使用union将两个表连起来

 1 Hibernate: 
2 select
3 max(ids_.ID)
4 from
5 ( select
6 ID
7 from
8 EXPRESS_DELIVERY
9 union
10 select
11 ID
12 from
13 POST_DELIVERY
14 ) ids_
15 Hibernate:
16 insert
17 into
18 POST_DELIVERY
19 (phone, address, POSTCODE, PARCEL_NUMBER, ID)
20 values
21 (?, ?, ?, ?, ?)

例子2:多态查询

1 Query query=session.createQuery("from Delivery");//查询父类得到所有子类的信息
2 List<Delivery> delivery=query.list();

3 for(Delivery d:delivery)
4 System.out.println(d.getAddress());

输出:

 1 Hibernate: 
2 select
3 delivery0_.ID as ID8_,
4 delivery0_.phone as phone8_,
5 delivery0_.address as address8_,
6 delivery0_.POSTCODE as POSTCODE8_,
7 delivery0_.PARCEL_NUMBER as PARCEL1_9_,
8 delivery0_.EXPRESS_COMPANY as EXPRESS1_10_,
9 delivery0_.EXPRESS_NUMBER as EXPRESS2_10_,
10 delivery0_.clazz_ as clazz_
11 from
12 ( select
13 ID,
14 phone,
15 address,
16 null as EXPRESS_NUMBER,
17 POSTCODE,
18 PARCEL_NUMBER,
19 null as EXPRESS_COMPANY,
20 1 as clazz_
21 from
22 POST_DELIVERY
23 union
24 select
25 ID,
26 phone,
27 address,
28 EXPRESS_NUMBER,
29 POSTCODE,
30 null as PARCEL_NUMBER,
31 EXPRESS_COMPANY,
32 2 as clazz_
33 from
34 EXPRESS_DELIVERY
35 ) delivery0_
36 北京西街15号
37 苏州通信大楼2F

可见Hibernate把两个子类对应的表的字段合并起来,执行效率低。建议用于父类将来不会修改且不需要多态查询的情况。

(3)父类子类各有一表,用外键关联,子类表的主键为外键引用父类表的主键

 1 /*mysql*/
2 create table delivery
3 (
4 id int primary key auto_increment,
5 phone varchar(20),
6 address varchar(200) not null,
7 postcode varchar(20)
8 );
9 create table post_delivery
10 (
11 id int primary key,
12 parcel_number varchar(20),
13 foreign key(id) references delivery(id)
14 );
15
16 create table express_delivery
17 (
18 id int primary key,
19 express_company varchar(20),
20 express_number varchar(20),
21 foreign key(id) references delivery(id)
22 );

例子1:单独子类操作

1         PostDelivery pDelivery=new PostDelivery();
2 pDelivery.setPhone("13526356485");
3 pDelivery.setAddress("北京西街15号");
4 pDelivery.setPostcode("100080");
5 pDelivery.setParcelNumber("8578");
6 session.save(pDelivery);

输出:

 1 Hibernate: 
2 insert
3 into
4 DELIVERY
5 (phone, address, POSTCODE)
6 values
7 (?, ?, ?)
8 Hibernate:
9 insert
10 into
11 POST_DELIVERY
12 (PARCEL_NUMBER, id)
13 values
14 (?, ?)

例子2:多态查询

 1 Hibernate: 
2 select
3 delivery0_.ID as ID8_,
4 delivery0_.phone as phone8_,
5 delivery0_.address as address8_,
6 delivery0_.POSTCODE as POSTCODE8_,
7 delivery0_1_.PARCEL_NUMBER as PARCEL2_9_,
8 delivery0_2_.EXPRESS_COMPANY as EXPRESS2_10_,
9 delivery0_2_.EXPRESS_NUMBER as EXPRESS3_10_,
10 case
11 when delivery0_1_.id is not null then 1
12 when delivery0_2_.id is not null then 2
13 when delivery0_.ID is not null then 0
14 end as clazz_
15 from
16 DELIVERY delivery0_
17 left outer join
18 POST_DELIVERY delivery0_1_
19 on delivery0_.ID=delivery0_1_.id
20 left outer join
21 EXPRESS_DELIVERY delivery0_2_
22 on delivery0_.ID=delivery0_2_.id
23 北京西街15号
24 苏州通信大楼2F

符合数据模型的常规设计规则,类与表的映射匹配更合理。缺点是复杂的类继承下新增数据需要同时操作多个表,查询时通过多个表连接。适用于需要多态查询,同时子类相对来说有较多的新增属性。










posted @ 2011-12-26 14:27  tazi  阅读(1167)  评论(0编辑  收藏  举报