如何将继承策略与多个子类层相结合



我正在尝试优化我的数据库表。但是我对Hibernate/JPA缺乏了解,这对我现在没有多大帮助。

我有一个Java对象模型,它看起来或多或少像这样:

ParentClass
  SubClass1
    SubSubClass1
    SubSubClass2
    SubSubClass3
    SubSubClass4
  SubClass2
    SubSubClass5
    SubSubClass6

所有类都包含字段。大约50%的字段在ParentClass中。40-50%处于SubClass1级别,0-10%处于SubSubSubclass级别。许多SubSubClass*类是空的,但却是标识类型所必需的。

TRY 1:

所以。我们首先做的是在Parentclass上使用TABLE_PER_CLASS策略。这导致了大量的表格:

SubSubClass1
SubSubClass2
SubSubClass3
SubSubClass4
SubSubClass5
SubSubClass6

这不是很酷,因为这些表中50%的所有列在所有表之间共享,而其余部分在3-4个表之间共享。

TRY 2:

我们将策略更改为SINGLE_TABLE。

生成的表只是一个大的"ParentClass"表。但由于只有大约50%的列在所有子类之间共享,所以许多字段必须设置为Null,这就不那么性感了。

TRY 3:

下一次尝试是将TABLE_PER_CLASS策略与"SINGLE_TABLE"策略混合使用。我决定不使用JOIN TABLES作为一种策略,因为我必须有许多小的子类,这会导致创建许多内部有一到两列的小表。

所以,我在这个问题中得到了以下答案:如何将继承策略与JPA注释和Hibernate混合?

我现在想把ParentClass的所有值放在一个表中,把第一个子级别的所有值都放在一张表中。这应该会产生这样的模式:

ParentClass
 - SubClass1
 - SubClass2
 - SubClass3

这是我的代码:

@MappedSuperclass
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class ParentClass {
  private String value1;
}
@MappedSuperclass
@SecondaryTable(name = "SubClass1")
public abstract class SubClass1 extends ParentClass {
  @Column(table = "SubClass1")
  private String value11;
}
@MappedSuperclass
@SecondaryTable(name = "SubClass2")
public abstract class SubClass2 extends ParentClass {
  @Column(table = "SubClass2")
  private String value12;
}

@Entity
@SecondaryTable(name = "SubClass1")
public abstract class SubSubClass1 extends SubClass1 {
  @Column(table = "SubClass1")
  private String value111;
}
@Entity
@SecondaryTable(name = "SubClass2")
public abstract class SubSubClass2 extends SubClass2 {
  @Column(table = "SubClass2")
  private String value121;
}

实际上效果很好但我的问题开始了:

首先,我在SchemaUpdate过程中得到以下错误。

Unsuccessful: alter table schema.SubClass1 add constraint AAAAAAA36D68C4 foreign key (id) references schema.ParentClass
ORA-02275: such a referential constraint already exists in the table
Unsuccessful: alter table schema.SubClass2 add constraint AAAAAAA36D68C4 foreign key (id)  references schema.ParentClass
ORA-02275: such a referential constraint already exists in the table

我认为这些错误是由于我在多个级别上多次使用SecondaryTables而导致的。每次使用它们时,都会创建另一个约束。这当然不起作用,因为约束已经存在。

第二个问题是,如果Hibernate应该从所有这些表中获取数据,那么它就会发疯:

select
    * 
from
    ( select
        parentclass0_.value1 as value1_1_,
        parentclass0_1_.value11 as erste1_3_,
        parentclass0_1_.value111 as value1113_3_,
        parentclass0_2_.value12 as value122_3_,
        parentclass0_2_.value121 as value1214_3_,
        parentclass0_.DTYPE as DTYPE2_ 
    from
        schema.parentclass parentclass0_ 
    left outer join
        schema.subclass1 parentclass0_1_ 
            on parentclass0_.id=parentclass0_1_.id 
    left outer join
        schema.subclass1 parentclass0_2_ 
            on parentclass0_.id=parentclass0_2_.id 
    left outer join
        schema.subclass1 parentclass0_3_ 
            on parentclass0_.id=parentclass0_3_.id 
    left outer join
        schema.subclass2 parentclass0_4_ 
            on parentclass0_.id=parentclass0_4_.parentclass_id 
    left outer join
        schema.subclass1 parentclass0_5_ 
            on parentclass0_.id=parentclass0_5_.id 
    left outer join
        schema.subclass1 parentclass0_6_ 
            on parentclass0_.id=parentclass0_6_.id ) 

每当我在子类中使用@SecondaryTable注释时,它都会加入同一个表。它一次又一次地加入其中。我看了Oracle的解释计划,它告诉我,如果我要优化它,这个计划会自动优化到我要使用的内容。但无论如何。这很奇怪。

问题:

如何防止Hibernate多次创建相同的约束我认为这也可以解决联接问题。或者应该停止尝试这样做,还有其他方法吗?

从纯JPA的角度来看,不能在继承树中混合策略。引用JPA规范(11.1.20)

继承注释定义了要使用的继承策略对于实体类层次结构。它是在实体类上指定的这是实体类层次结构的根。本规范不要求支持继承策略的组合。可移植应用程序应仅在实体层次结构中使用单一继承策略。

JDO是唯一允许您在树下定义不同策略的持久性规范。

我认为您应该真正使用SINGLE_TABLE策略。50%的共享列确实没有那么糟糕,特别是如果你知道这个数字不会随着时间的推移而减少(我的意思是,你认为有一天该表中会有500列,而只有40列共享吗?),并且如果你要对根实体运行大量查询,而根实体总是与其他策略进行多次连接。

在工作中,我们刚刚讨论过这个问题。之所以选择SINGLE_TABLE策略,是因为我们不认为列的数量会爆炸式增长,并且我们可能只得到5%的共享属性:(。所以我认为这对您的情况有效,但要小心,并考虑如何访问您的数据。

编辑:由于不可能混合策略,而且您不需要太多表格:如果你有140个子实体和50%的共享属性,你真的应该真正使用SINGLE_TABLE策略!!!!!!

为什么不在父类上使用JOINED策略?您仍然会有很多表,但没有多余的属性。

最新更新