Когда JPA устанавливает @GeneratedValue @Id

У меня есть простая сущность 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 ответа

Решение

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

Томас

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

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

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

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

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

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

А также что EntityManager.persist() марки

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

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


тем не мение

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

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

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

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

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

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

Другие вопросы по тегам