[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);
类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);