如何将inheritance策略与JPA注释和Hibernate混合?
根据Hibernate参考文档 ,在使用Hibernate的XML-Metadata时,应该可以混合使用不同的inheritance映射策略:
http://docs.jboss.org/hibernate/stable/core/reference/en/html/inheritance.html#inheritance-mixing-tableperclass-tablepersubclass
但是,“ Hibernate注解参考指南”的相应部分并不包括:
http://docs.jboss.org/hibernate/stable/annotations/reference/en/html/entity.html#d0e1168
另一方面,JavaDocsbuild议混合inheritance策略应该是可能的。 例如在javax.persistence.DiscriminatorColumn中它说:
策略和鉴别器列仅在应用不同inheritance策略的实体类层次结构或子层次结构的根目录中指定。
以下是我试图实现的映射的一个示例。 我想在层次结构的根目录附近使用table-per-subclass映射,但是在树叶附近改变为table-per-class-hierarchy映射。 以下是一些示例代码:
@Entity @Inheritance( strategy = InheritanceType.JOINED ) public abstract class A implements Serializable { @Id private String id; // other mapped properties... } @Entity @Inheritance( strategy = InheritanceType.SINGLE_TABLE ) public class BB extends A { // other mapped properties and associations... } @Entity public class BB1 extends BB { // other stuff, not necessarily mapped... } @Entity public class BB2 extends BB { // other stuff, not necessarily mapped... } @Entity @Inheritance( strategy = InheritanceType.SINGLE_TABLE ) public class CC extends A { // other mapped properties and associations... } @Entity public class CC1 extends CC { // other stuff, not necessarily mapped... } ...
我对这个映射的期望是正好有3个表: A
, BB
和CC
。 BB
和CC
都应该有一个名为DTYPE
的默认鉴别器列。 他们还应提供所有映射的属性和它们各自的子类的关联所需的所有列。
相反,类层次结构似乎始终使用每个子类inheritance策略。 也就是说,我为上面提到的每个实体都有一个自己的表格。 我想避免这种情况,因为类层次结构的叶子非常轻,看起来每个人都有独立的桌子似乎太过于矫枉过正了!
我忽略了什么? 任何意见是高度赞赏! 我会很高兴提供更多信息…
根据Hibernate参考文档,当使用Hibernate的XML元数据(…)时,应该可以混合使用不同的inheritance映射策略。
实际上,它并不是真的被支持,它们在文档的例子中使用辅助表从单一表策略中切换到“作弊”。 用Hibernate引用Java持久性 :
您可以通过嵌套
<union-subclass>
,<sub- class>
和<joined-subclass>
映射元素来映射整个inheritance层次结构。 你不能混合它们 – 例如,从一个具有鉴别器的每个类的层次结构切换到一个规范化的每个子类的策略。 一旦你做出inheritance策略的决定,你必须坚持下去 。然而,这并不完全正确。 使用一些Hibernate技巧,您可以切换特定子类的映射策略。 例如, 可以将类层次结构映射到单个表,但是对于特定的子类,使用外键映射策略切换到单独的表 ,就像每个子类的表一样。 这可以通过
<join>
映射元素来实现:<hibernate-mapping> <class name="BillingDetails" table="BILLING_DETAILS"> <id>...</id> <discriminator column="BILLING_DETAILS_TYPE" type="string"/> ... <subclass name="CreditCard" discriminator-value="CC"> <join table="CREDIT_CARD"> <key column="CREDIT_CARD_ID"/> <property name="number" column="CC_NUMBER"/> <property name="expMonth" column="CC_EXP_MONTH"/> <property name="expYear" column="CC_EXP_YEAR"/> ... </join> </subclass> <subclass name="BankAccount" discriminator-value="BA"> <property name=account" column="BA_ACCOUNT"/> ... </subclass> ... </class> </hibernate-mapping>
你可以通过注释来实现:
Java Persistence也支持这种带有注释的混合inheritance映射策略。 像之前
BillingDetails
使用InheritanceType.SINGLE_TABLE
映射超类BillingDetails
。 现在,将要从单个表中分出的子类映射到辅助表。@Entity @DiscriminatorValue("CC") @SecondaryTable( name = "CREDIT_CARD", pkJoinColumns = @PrimaryKeyJoinColumn(name = "CREDIT_CARD_ID") ) public class CreditCard extends BillingDetails { @Column(table = "CREDIT_CARD", name = "CC_NUMBER", nullable = false) private String number; ... }
我没有testing这个,但你也许可以尝试:
- 映射A使用SINGLE_TABLE策略
- 使用
@SecondaryTable
注解映射BB,CC等。
我没有testing过这个,我不知道它是否适合BB1,BB2。
参考
- Java持久与Hibernate
- 5.1.5混合遗传策略(p207-p210)
只是为了清楚起见,这里是帕斯卡的解决scheme适用于我的问题的示例代码:
@Entity @Inheritance( strategy = InheritanceType.SINGLE_TABLE ) @DiscriminatorColumn( name = "entityType", discriminatorType = DiscriminatorType.STRING ) public abstract class A implements Serializable { @Id private String id; // other mapped properties... } @Entity @SecondaryTable( name = "BB" ) public class BB extends A { @Basic( optional = false) @Column( table = "BB" ) private String property1; // other mapped properties and associations... } @Entity public class BB1 extends BB { // other stuff, not necessarily mapped... } @Entity public class BB2 extends BB { // other stuff, not necessarily mapped... } @Entity @SecondaryTable( name = "CC" ) public class CC extends A { @ManyToOne( optional = false) @JoinColumn( table = "CC" ) private SomeEntity association1; // other mapped properties and associations... } @Entity public class CC1 extends CC { // other stuff, not necessarily mapped... } ...
我已经成功地将这个方法应用于我的问题,我暂时坚持下去。 但是我仍然看到以下缺点:
-
鉴别器列位于层次结构的主表中,即根元素
A
的表。 在我的情况下,在辅助表BB
和CC
有鉴别器列就足够了。 -
任何时候,只要将属性和关联添加到
BB
或CC
子类,他/她就必须指定它们应该映射到相应的辅助表。 会很好,如果有一种方法来使默认。