Когда 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.