一对多关系的一次有趣实践

[i]不好给本贴取名,暂且看吧。[/i]

类A 和 类B 具有[b]一对多[/b]的关系。A有子类 A1 和 A2,且A1和A2的字段个数和种类相差较大。
系统对A的检索/查找要求较低,对B的检索/查找功能较多也较重要。

表设计如下:
A采用TABLE_PER_CLASS的方式[b],即A1和A2各一张表TABLE_A1, TABLE_A2[/b]。
(系统不会有同时列出A1和A2的查询,也可以容忍A1和A2可重复一个ID)
类B映射为一个表TABLE_B,并设置了一个[b]外键A_ID[/b],关联对B的关系。

OK!现在如何让系统知道A_ID对应的是TABLE_A1,还是TABLE_A2?

习惯从数据库角度看问题的,可以这样解决:
在TABLE_B中增加一个字段[b]type[/b],当type="A1"时,外键A_ID代表关联到TABLE_A1表。当="A2"时,外键A_ID代表关联到TABLE_A2表。
(其它方式的,比如规定A1主键和A2主键进行规则区分等等方案暂不考虑)

但[b]如何在Hibernate配置这种关系[/b]?翻了Hibernate的参考手册可没直接这方面的资料。

好在B在现实中也确实存在分类的问题,那就这样吧:


[code]

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "type")
public abstract class B {
// ...省略主键以及其他属性的

protected A a;

@Entity
@DiscriminatorValue(value = "A1")
public static class B1 extends B {
@Override
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "A_ID")
public A1 getA() {
return (A1) a;
}
}

@Entity
@DiscriminatorValue(value = "A2")
public static class B2 extends B {
@Override
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "A_ID")
public A2 getA() {
return (A2) a;
}
}

//这里需要配置Transient,子类需override本方法负责具体映射
@Transient
public A getA() {
return a;
}

public void setA(A a) {
this.a = a;
}
}

[/code]
配置文件大概是这样的(关键是要把B$B1, B$B2, A1, A2列进去,而A基本可以不列进去):

[code]<mapping class="com.yourapp.domain.B" />
<mapping class="com.yourapp.domain.B$B1" />
<mapping class="com.yourapp.domain.B$B2" />
<mapping class="com.yourapp.domain.A1" />
<mapping class="com.yourapp.domain.A2" />[/code]

经实践,这种方式用起来很顺畅,能够通过以下测试(测试期间一个事务保持Sesison不会被关闭):

B b1 = bDao.loadById(某实际是B.B1类的纪录ID);
assertEquals(B.B1.class, b1.getClass());

B b2 = bDao.loadById(某实际是B.B2类的纪录ID);
assertEquals(B.B2.class, b2.getClass());

A a1 = b1.getA();
assertNotEquals(A1.class, a1.getClass());//Lazy的缘故导致不等
assertTrue(a1 instanceof A1);

A a2 = b2.getA();
assertNotEquals(A2.class, a2.getClass());
assertTrue(a2 instanceof A2);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值