Когда 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 и, возможно, для разных стратегий генерации. Но что является самым безопасным (переносимым, соответствующим спецификации) предположением, которое вы можете сделать о самой ранней точке жизненного цикла, которую он установил?
Ответы
Ответ 1
вызов .perist() не будет автоматически устанавливать значение id. Ваш поставщик JPA гарантирует, что он будет установлен до того, как сущность будет окончательно записана в db. Поэтому вы правы предположить, что идентификатор будет назначен при совершении транзакции. Но это не единственный возможный случай. Когда вы вызовете .flush(), произойдет то же самое.
Томас
Обновление: обратите внимание на комментарий Geek, пожалуйста. → Если используется GenerationType.Identity, идентификатор не будет установлен поставщиком, прежде чем сущность будет записана на db. В этом случае генерация id происходит во время процесса вставки на уровне db. Во всяком случае, поставщик JPA будет гарантировать, что сущность будет обновляться впоследствии, и сгенерированный идентификатор будет доступен в аннотированном свойстве @Id.
Ответ 2
AFAIK, идентификатор гарантированно будет присваиваться только тогда, когда контекст сохранения сохраняется. Его можно назначить раньше, но это зависит от стратегии генерации.
Ответ 3
В книге Enterprise JavaBeans 3.1 от Rubinger и Burke говорится следующее: на стр. 143 (выделено мной):
Java Persistence также может быть настроена на автоматическое создание первичного ключа , когда метод persist()
вызывается с помощью аннотации @GeneratedValue
поверх поля первичного ключа или сеттера. Таким образом, в предыдущем примере, если бы мы включили автоматическое создание ключей, мы могли бы просмотреть сгенерированный ключ после завершения метода persist()
.
Спецификация JPA говорит (выделено мной):
Экземпляр управляемого объекта - это экземпляр с постоянным идентификатором, который в настоящее время связан с контекстом персистентности.
А также, что EntityManager.persist()
делает
управляемый экземпляр и постоянный
Поскольку @Id
имеет решающее значение для идентичности объекта, единственный способ для EntityManager.persist()
сделать управляемый объект - установить его идентификатор, создав @Id
.
Однако
Четкое утверждение Rubinger и Buke несовместимо с поведением Hibernate. Таким образом, кажется, что знающие люди не согласны с тем, что намерена спецификация JPA.
Ответ 4
В соответствии с JSR 338: Настойчивость JavaTM 2.1/3.5.3 Семантика методов обратного вызова жизненного цикла для объектов,
Методы обратного вызова PostPersist
и PostRemove
вызываются для объекта после того, как объект был сделан постоянным или удаленным. Эти обратные вызовы также будут вызываться для всех объектов, к которым эти операции каскадируются. Методы PostPersist
и PostRemove
будут вызываться после операций вставки и удаления базы данных соответственно. Эти операции с базой данных могут возникать непосредственно после того, как были вызваны операции persist, merge или remove или они могут возникнуть непосредственно после выполнения операции flush (которая может быть в конце транзакции). Сгенерированные значения первичного ключа доступны в PostPersist
.
Одним из возможных (лично предполагаемых) исключений является GeneratorType.TABLE
, который контейнер (может) извлекает значения для использования и (может) устанавливать его раньше PrePersist
. Я всегда использую id
в PrePersist
. Я не уверен, что это поведение указано или может не работать с другими поставщиками.
важное изменение
Не все серверы приложений устанавливают идентификатор до PrePersist
. Вы можете отслеживать JPA_SPEC.