JPA / Hibernate — InheritanceType.JOINED ведет себя как InheritanceType.TABLE_PER_CLASS

#java #hibernate #jpa

#java #переход в спящий режим #jpa

Вопрос:

Я пытаюсь реализовать очень простую модель наследования в Hibernate. В принципе, у меня есть один суперкласс, который можно вызвать A , и несколько подклассов, все из которых наследуются от A . Поскольку поведение, которое я вижу, одинаково для всех из них, на них можно просто ссылаться как B .

То, к чему я пытаюсь прийти, это то, что описано здесь в разделе 6.2. В принципе, должна быть таблица для A , которая содержит его поля, и таблица для B , которая содержит только поля, отличные от подкласса, плюс столбец объединения обратно в таблицу для A . Я использую автоматическую генерацию схемы Hibernate (включена только для модуля сохранения разработки).

Однако, когда я смотрю на схему, я вижу таблицу для A , которая содержит ее поля (правильно), и таблицу для B , которая содержит все поля в A (неправильно), плюс поля, добавленные в B . Мои классы аннотируются следующим образом:

 @Entity
@Table(name="A")
@Inheritance(strategy = InheritanceType.JOINED)
public class A implements Serializable {
    protected long id;
    protected Date createDate;
    protected String title;
    protected boolean hidden;

    public A() {
    }

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    public long getId() {
        return id;
    }

    @Column(nullable = false)
    @Temporal(TemporalType.TIMESTAMP)
    public Date getCreateDate() {
        return createDate;
    }

    @Column(nullable = false)
    public boolean isHidden() {
        return hidden;
    }

    @Column(nullable = false)
    public String getTitle() {
        return title;
    }

    //also setters...   
}

@Entity
@Table(name="B")
@PrimaryKeyJoinColumn(name="aId", referencedColumnName="id")
public class B extends A {
    private String extraField;

    public B() {
        super();
    }

    @Column
    public String getExtraField() {
        return extraField;
    }

    //also setter...
}
  

Есть идеи, что я сделал не так? В частности, то, что я хочу видеть при просмотре сгенерированной схемы БД, выглядит примерно так:

 Table A:  {id, createDate, title, hidden}
Table B:  {aId, extraField}
  

… и вместо этого я получаю:

 Table A:  {id, createDate, title, hidden}
Table B:  {id, createDate, title, hidden, extraField}
  

Это просто невозможно с помощью автоматической генерации схемы Hibernate, или я где-то перепутал аннотации?

Ответ №1:

Ваша аннотация верна, она должна создать схему таблицы, которую вы хотите.

Но теперь вы получаете нежелательную схему, которая в точности соответствует схеме, созданной с использованием Table per concrete class стратегии (т. е. @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) ). Итак, я думаю, что одна из возможных причин заключается в том, что hibernate.hbm2ddl.auto свойство в вашей конфигурации использует значение по умолчанию, которое является update .

Поведение update значения является :

  • Hibernate попытается создать сценарий обновления, чтобы обновить схему базы данных до текущего сопоставления при SessionFactory создании.

  • Если оператор update не может быть выполнен, он будет пропущен (например, добавление столбца not null в таблицу с существующими данными)

  • Режим гибернации не удалит никаких данных во время обновления.(Например, если имя столбца изменено, он просто добавляет новый столбец с новым именем, но при этом сохраняет столбец с исходным именем)

Итак, я думаю, вы должны использовать @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) для генерации схемы ранее, которая создала следующую схему . Таблица A и таблица B не имеют никаких ассоциаций внешнего ключа друг с другом.

 Table A:  {id, createDate, title, hidden}
Table B:  {id, createDate, title, hidden, extraField}
  

После этого вы изменили режим использования @Inheritance(strategy = InheritanceType.JOINED) . В процессе обновления схемы hibernate просто обновил вашу схему, добавив ассоциацию внешнего ключа между TableA.id и TableB.id . Он сохранил все остальные столбцы в таблице B. Вот почему вы получаете текущую схему, даже если ваша аннотация верна.

Желаемая схема таблицы должна быть сгенерирована после удаления таблиц A и B из базы данных перед запуском программы гибернации . В качестве альтернативы вы можете установить hibernate.hbm2ddl.auto значение create , тогда hibernate удалит все таблицы перед созданием схемы таблицы .

Комментарии:

1. Спасибо, я не думаю, что я когда-либо использовал InheritanceType.TABLE_PER_CLASS , но в любом случае удаление таблиц и разрешение Hibernate регенерировать схему, как вы предложили, исправили ситуацию.