论坛首页 Java企业应用论坛

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

浏览 1857 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2007-11-10  
不好给本贴取名,暂且看吧。

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

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

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

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

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

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


 

@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;
	}
}


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

<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" />


经实践,这种方式用起来很顺畅,能够通过以下测试(测试期间一个事务保持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);
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics