Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement a callback when entity is persisted?

I have a very simple entity, as:

@Entity
public class entityA {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    private Long id;

    public entityA(){}

}

As far as I understood the value id is only set if the entity is persisted. Is this correct?

Since I want to propagate the value of the id to some observers, this only makes sense after the item is persisted. So I need some kind of callback (something like void onPersit()) in entityA. The method entityA.onPersit() shall be automatically be executed if the entity is persisted. How to implement this?

(How) can an entity determin it's own status. E.g. is there some kind of this.isPersisted() or this.isDetached()?

like image 677
BerndGit Avatar asked Nov 02 '16 16:11

BerndGit


People also ask

What callback will be invoked after saving an entity to the database?

Entity lifecycle callback methods can be defined on the entity class and are invoked when the entity state changes. These methods are useful for validating entity fields and updating transient state that is not usually persisted with the entity.

How do you implement callbacks?

To implement a callback functionCreate the managed callback function. The example declares a delegate type, called CallBack , which takes two arguments (hwnd and lparam). The first argument is a handle to the window; the second argument is application-defined. In this release, both arguments must be integers.

What callback is executed before deleting an entity in the underlying database?

Executed before the entity manager remove operation is actually executed or cascaded. This call is synchronous with the remove operation.

What is persisted entity?

Persistent (Managed) A persistent entity has been associated with a database table row and it's being managed by the currently running Persistence Context. Any change made to such an entity is going to be detected and propagated to the database (during the Session flush-time).


1 Answers

If I where you, I would go with the solution that is available in the JPA specification, the @PostPersist annotation. Your entity would look like this:

@Entity
public class entityA {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    private Long id;

    public entityA(){}

    @PostPersist
    public void onPersit() {
      // logic to perform after the entity has been persisted
    }

}

The Java Persistence 2.1 Specification explains the functionality like this:

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.

The above quote also answers your question if the generated primary key is only available after insertion to the database. Your assumption was right, but it will be available in the method annotated @PostPersist.


Regarding the question about having methods on the entity to check its state, the naive way is to check whether the @Id field is null or not. If the code is written by the book (i.e. doesn't modify the field itself), this will work.

However, there is a more sophisticated to achieve this, as proposed in this answer:

@Transient
private boolean persisted;

@PostLoad
@PostPersist
public void setPersisted() {
  persisted = true;
}

By using the @PostLoad and @PostPersist callbacks, this makes sure that the persisted field is set correctly. Again, you need to be sure you don't modify the field outside of this method. The @Transient annotation makes sure that the field is not a candidate for serialization, and as such is not persistent.

Either of these solutions could be placed in an abstract entity class for reusage across entities.

like image 111
Magnilex Avatar answered Sep 22 '22 18:09

Magnilex