Когда JPA устанавливает @GeneratedValue @Id - PullRequest
44 голосов
/ 01 февраля 2012

У меня есть простая сущность JPA, которая использует сгенерированный long "ID" в качестве своего первичного ключа:

@Entity
public class Player {
   private long id;

   protected Player() {
     // Do nothing; id defaults to 0L
   }


   @GeneratedValue
   @Id
   public long getId() {
      return id;
   }

   protected void setId(final long id) {
      this.id = id;
   }
   // Other code
}

В какой-то момент жизненного цикла объекта этого типа JPA должен вызвать setId(), чтобы записать сгенерированное значение идентификатора. У меня вопрос: , когда это происходит, и , где находится документация, в которой говорится . Я просмотрел спецификацию JPA и не могу найти четкого утверждения.

Спецификация JPA гласит (выделение добавлено):

Экземпляр управляемого объекта - это экземпляр с постоянным идентификатором , который в настоящее время связан с постоянным контекстом.

Это пытается сказать, что объект должен быть управляемым , чтобы иметь его @Id значимым? Документация для EntityManager.persist() говорит (выделение выделено), что делает "экземпляр управляемым и постоянным", значит ли это, что @Id устанавливается этим методом? Или пока вы не позвоните EntityTransaction.commit()?

Когда установлен @Id, может отличаться для разных поставщиков JPA и, возможно, для разных стратегий генерации. Но какое самое безопасное (переносимое, соответствующее спецификации) предположение, которое вы можете сделать о самом раннем этапе жизненного цикла, который был установлен?

Ответы [ 4 ]

21 голосов
/ 01 февраля 2012

вызов .persist () не будет автоматически устанавливать значение идентификатора.Ваш провайдер JPA удостоверится, что он установлен до того, как сущность будет наконец записана в db.Таким образом, вы правы, предполагая, что идентификатор будет назначен при совершении транзакции.Но это не единственный возможный случай.Когда вы вызываете .flush (), происходит то же самое.

Thomas

Обновление: обратите внимание на комментарий Geek, пожалуйста.-> Если используется GenerationType.Identity, провайдер не установит идентификатор до того, как сущность будет записана в БД.В этом случае генерация идентификатора происходит во время процесса вставки на уровне БД.В любом случае, провайдер JPA будет следить за тем, чтобы сущность обновлялась впоследствии, и сгенерированный идентификатор будет доступен в аннотированном свойстве @Id.

11 голосов
/ 01 февраля 2012

AFAIK, идентификатор гарантированно будет назначен только при сбросе контекста персистентности. Это может быть назначено раньше, но это зависит от стратегии генерации.

8 голосов
/ 26 февраля 2012

В книге Enterprise JavaBeans 3.1 Рубингера и Бёрка говорится на странице 143 следующее (выделение добавлено):

Сохранение Java также можно настроить для автоматической генерации первичногоклавиша , когда метод persist() вызывается посредством использования аннотации @GeneratedValue поверх поля первичного ключа или установщика.Таким образом, в предыдущем примере, если бы у нас была включена автоматическая генерация ключей, мы могли бы просмотреть сгенерированный ключ после завершения метода persist().

В спецификации JPA говорится (выделение добавлено):

Экземпляр управляемого объекта - это экземпляр с постоянным удостоверением , который в настоящее время связан с постоянным контекстом.

А также то, что EntityManager.persist() составляет

экземпляр, управляемый и постоянный

Поскольку @Id имеет решающее значение для идентичности объекта, единственный способ для EntityManager.persist() сделатьуправляемый объект должен установить свою идентичность путем генерации @Id.


Однако

Понятие ясности Рубингера и Бьюка противоречивос поведением Hibernate.Похоже, что знающие люди не согласны с тем, что намеревается спецификация JPA.

4 голосов
/ 27 июля 2016

Согласно JSR 338: JavaTM Persistance 2.1 / 3.5.3 Семантика методов обратного вызова жизненного цикла для объектов ,

Методы обратного вызова PostPersist и PostRemove вызываются для объекта после того, как объект становится постоянным или удаляется. Эти обратные вызовы также будут вызываться для всех объектов, для которых эти операции каскадируются. Методы PostPersist и PostRemove будут вызваны после операций вставки и удаления базы данных соответственно. Эти операции с базой данных могут происходить непосредственно после того, как были вызваны операции сохранения, слияния или удаления, или они могут происходить непосредственно после выполнения операции очистки (которая может быть в конце транзакции). Сгенерированные значения первичного ключа доступны в методе PostPersist .

Одним из возможных (лично предполагаемых) исключений является GeneratorType.TABLE, когда контейнер (может) извлекает значения для использования и (может) устанавливать его до PrePersist. Я всегда использую свой id в PrePersist. Я не уверен, что это поведение указано или может не работать с другими поставщиками.

важное редактирование

Не все серверы приложений устанавливают идентификатор до PrePersist. Вы можете отслеживать JPA_SPEC .

...