简体   繁体   中英

When does the JPA set a @GeneratedValue @Id

I have a simple JPA entity that uses a generated long "ID" as its primary key:

@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
}

At some point in the life-cycle of an object of this type the JPA must call setId() to record the generated ID value. My question is, when does this happen, and where is the documentation that states this . I've looked through the JPA Specification and can not find a clear statement.

The JPA Specification says (emphasis added):

A managed entity instance is an instance with a persistent identity that is currently associated with a persistence context.

Is that trying to say that the the object must be managed to have its @Id significant? The documentation for EntityManager.persist() says (emphasis added) it makes "an instance managed and persistent", so does that mean that the @Id is set by that method? Or is it not until you call EntityTransaction.commit() ?

When the @Id is set might be different for different JPA providers, and perhaps for different generation strategies. But what is the safest (portable, specification conforming) assumption that you can make about the earliest point in the lifecycle that it has been set?

calling .persist() will not automatically set the id value. Your JPA provider will ensure that it is set before the entity is finally written to db. So you are right to assume that the id will be assigned when the transaction is committed. But this is not the only possible case. When you call .flush() the very same will happen.

Thomas

Update: Pay attention to Geek's comment, please. -> If GenerationType.Identity is used, the id will not be set by the provider before the entity is written to db. In this case id generation happens during the insert process on db level. Anyway, the JPA provider will ensure that the entity is updated afterwards and the generated id will be available in the @Id annotated property.

AFAIK, the ID is only guaranteed to be assigned when the persistence context is flushed. It might be assigned sooner, but it depends on the generation strategy.

The book Enterprise JavaBeans 3.1 by Rubinger and Burke says the following, on page 143 (emphasis added):

Java Persistence can also be configured to automatically generate a primary key when the persist() method is invoked through the use of the @GeneratedValue annotation atop the primary key field or setter. So, in the previous example, if we had auto key generation enabled, we could view the generated key after the persist() method completed.

The JPA Specification says (emphasis added):

A managed entity instance is an instance with a persistent identity that is currently associated with a persistence context.

And also that EntityManager.persist() makes

an instance managed and persistent

As the @Id is crucial to the identity of an entity, the only way for EntityManager.persist() to make the object managed is to establish its identity by generating the @Id .


However

Rubinger and Buke's clear statement is inconsistent with the behaviour of Hibernate. So it seems that knowledgeable people disgree about what the JPA specification intends.

According to JSR 338: JavaTM Persistence 2.1 / 3.5.3 Semantics of the Life Cycle Callback Methods for Entities ,

The PostPersist and PostRemove callback methods are invoked for an entity after the entity has been made persistent or removed. These callbacks will also be invoked on all entities to which these operations are cascaded. The PostPersist and PostRemove methods will be invoked after the database insert and delete operations respectively. These database operations may occur directly after the persist, merge, or remove operations have been invoked or they may occur directly after a flush operation has occurred (which may be at the end of the transaction). Generated primary key values are available in the PostPersist method .

One possible (personally presumable) exception is GeneratorType.TABLE which the container (may) fetches values to use and (may) set it before PrePersist . I always use my id in PrePersist . I'm not sure this behaviors is specified or may not work with any other vendors.

important edit

Not all application servers set id before PrePersist . You can track JPA_SPEC .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM