Как смешать стратегии наследования в сочетании с несколькими слоями подкласса - PullRequest
3 голосов
/ 01 марта 2012

Я пытаюсь немного оптимизировать свои таблицы базы данных. Но мое непонимание Hibernate / JPA сейчас не сильно помогает.

У меня есть объектная модель Java, которая выглядит примерно так:

ParentClass
  SubClass1
    SubSubClass1
    SubSubClass2
    SubSubClass3
    SubSubClass4
  SubClass2
    SubSubClass5
    SubSubClass6

Все классы содержат поля. Около 50% всех полей находятся в ParentClass. 40-50% находятся на уровне подкласса 1, а 0-10% находятся на уровне подкласса. Многие из классов SubSubClass * пусты, но необходимы для идентификации типа.

TRY 1:

Так. Сначала мы использовали стратегию 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 создавать одно и то же ограничение несколько раз? Думаю, это также решит проблему объединения. Или следует прекратить попытки сделать это так и есть ли другой способ?

Ответы [ 3 ]

9 голосов
/ 01 марта 2012

С точки зрения чисто JPA, вы НЕ МОЖЕТЕ СМЕШАТЬ стратегии в дереве наследования.Чтобы процитировать спецификацию JPA (11.1.20)

Аннотация Наследование определяет стратегию наследования, которая будет использоваться для иерархии классов сущностей.Он указывается в классе сущностей, который является корнем иерархии классов сущностей.Поддержка комбинации стратегий наследования не требуется в данной спецификации.Переносимые приложения должны использовать только одну стратегию наследования в иерархии объектов.

JDO - это единственная спецификация персистентности, которая позволяет вам определять различные стратегии в древовидной структуре.

2 голосов
/ 02 марта 2012

Я думаю, что вы действительно должны использовать стратегию SINGLE_TABLE.50% общих столбцов ДЕЙСТВИТЕЛЬНО не так уж плохи, особенно если вы знаете, что число не будет уменьшаться со временем (я имею в виду, думаете ли вы, что однажды в этой таблице будет 500 столбцов с общим количеством только 40 столбцов?), Иесли вы собираетесь выполнить много запросов к корневому объекту, который всегда будет выполнять много соединений с другой стратегией.

На работе мы только что обсуждали это.Стратегия SINGLE_TABLE была выбрана потому, что мы не думали, что количество столбцов взорвется, и у нас может закончиться только 5% общих свойств :(. Поэтому я думаю, что это будет работать для вашего случая, но позаботьтесь и подумайте, как ваши данные будут работатьбыть доступным.

Редактировать: поскольку невозможно смешивать стратегии и вам не нужно много таблиц: если у вас есть 140 дочерних сущностей и 50% общих атрибутов, вы действительно должны использовать стратегию SINGLE_TABLE!!!!!!

0 голосов
/ 01 марта 2012

Почему вы не используете стратегию JOINED в родительском классе?У вас все равно будет много таблиц, но нет избыточных атрибутов.

...