Вопрос-ответ

Hibernate JPA Sequence (non-Id)

Последовательность JPA гибернации (без идентификатора)

Возможно ли использовать последовательность DB для некоторого столбца, который не является идентификатором / не является частью составного идентификатора?

Я использую hibernate в качестве поставщика jpa, и у меня есть таблица, в которой есть несколько столбцов, которые являются сгенерированными значениями (с использованием последовательности), хотя они не являются частью идентификатора.

Я хочу использовать последовательность для создания нового значения для объекта, где столбец для последовательности НЕ является (частью) первичного ключа:

@Entity
@Table(name = "MyTable")
public class MyEntity {

//...
@Id //... etc
public Long getId() {
return id;
}

//note NO @Id here! but this doesn't work...
@GeneratedValue(strategy = GenerationType.AUTO, generator = "myGen")
@SequenceGenerator(name = "myGen", sequenceName = "MY_SEQUENCE")
@Column(name = "SEQ_VAL", unique = false, nullable = false, insertable = true, updatable = true)
public Long getMySequencedValue(){
return myVal;
}

}

Затем, когда я делаю это:

em.persist(new MyEntity());

идентификатор будет сгенерирован, но mySequenceVal свойство также будет сгенерировано моим провайдером JPA.

Просто чтобы внести ясность: я хочу, чтобы Hibernate генерировал значение для mySequencedValue свойства. Я знаю, что Hibernate может обрабатывать значения, генерируемые базой данных, но я не хочу использовать триггер или любую другую вещь, кроме самого Hibernate, для генерации значения для моего свойства. Если Hibernate может генерировать значения для первичных ключей, почему он не может генерировать для простого свойства?

Переведено автоматически
Ответ 1

В поисках ответов на эту проблему я наткнулся на эту ссылку

Похоже, что Hibernate / JPA не может автоматически создавать значение для ваших свойств без идентификатора. @GeneratedValue Аннотация используется только в сочетании с @Id для создания автоматических номеров.

В @GeneratedValue аннотации просто сообщается Hibernate, что база данных сама генерирует это значение.

Решение (или обходной путь), предложенное на этом форуме, заключается в создании отдельного объекта с сгенерированным идентификатором, что-то вроде этого:

@Entity 
общедоступный класс GeneralSequenceNumber {
@Id
@GeneratedValue(...)
закрытый длинный номер;
}

@Entity
публичный класс MyEntity {
@Id ..
закрытый длинный идентификатор;

@OneToOne(...)
private GeneralSequnceNumber myVal;
}
Ответ 2

Я обнаружил, что @Column(columnDefinition="serial") работает идеально, но только для PostgreSQL. Для меня это было идеальное решение, потому что second entity - "уродливый" вариант.

Также необходим вызов saveAndFlush для объекта, и save этого будет недостаточно для заполнения значения из базы данных.

Ответ 3

Я знаю, что это очень старый вопрос, но сначала он показан по результатам, и jpa сильно изменился с момента постановки вопроса.

Правильный способ сделать это сейчас - использовать @Generated аннотацию. Вы можете определить последовательность, установить значение по умолчанию в столбце на эту последовательность, а затем отобразить столбец как:

@Generated(GenerationTime.INSERT)
@Column(name = "column_name", insertable = false)
Ответ 4

Hibernate определенно поддерживает это. Из документов:

"Сгенерированные свойства - это свойства, значения которых генерируются базой данных. Обычно приложениям гибернации требовалось обновить объекты, содержащие какие-либо свойства, для которых база данных генерировала значения. Однако пометка свойств как сгенерированных позволяет приложению делегировать эту ответственность Гибернации. По сути, всякий раз, когда Hibernate выдает SQL INSERT или UPDATE для объекта, который определил сгенерированные свойства, он сразу же выдает select для извлечения сгенерированных значений."

Для свойств, созданных только при вставке, ваше сопоставление свойств (.hbm.xml) будет выглядеть следующим образом:

<property name="foo" generated="insert"/>

Для свойств, сгенерированных при вставке и обновлении сопоставления свойств (.hbm.xml), будет выглядеть следующим образом:

<property name="foo" generated="always"/>

К сожалению, я не знаю JPA, поэтому я не знаю, доступна ли эта функция через JPA (я подозреваю, что, возможно, нет)

В качестве альтернативы вы должны иметь возможность исключить свойство из вставок и обновлений, а затем "вручную" вызвать session.refresh( obj ); после того, как вы вставили / обновили его, чтобы загрузить сгенерированное значение из базы данных.

Таким образом можно исключить использование свойства в операторах insert и update:

<property name="foo" update="false" insert="false"/>

Опять же, я не знаю, предоставляет ли JPA эти функции гибернации, но Hibernate их поддерживает.

2023-09-24 23:31 java hibernate jpa