Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EclipseLink JPA `@PreUpdate` call not persisting

I ran into some similar questions on StackOverflow, tried the solutions, but did not find an answer.

I am using a fairly common JPA strategy to set last modified times on some entities. Set up the columns and the fields, then tag a method with @PreUpdate and let it set them equal to the current time.

The problem is that I can see in the debugger that the method is being called and that the field is being updated, however in my DB logs I only see a SQL call to UPDATE the changed field that does NOT include an UPDATE for the timestamp field.

Complicating things further @PrePersist works perfectly, only @PreUpdate exibits this behaviour.

The closest explanation I've found so far is at this LINK.

Similar questions at: #1725699 and #1745890

I am using EclipseLink v2 and JPA v1 for compatibility with GlassFish v2.

I have attempted using both annotations directly on methods in the Entity class as well as an EntityListener attached to the Entity class with the @EntityListener annotation.

I suspect this is a bug in EclipseLink, but I can't prove it.

Bug or not I would very much like this simple operation to work. Is there anything wrong with this implementation? Is this a known issue in EclipseLink? Is this a known issue in JPA? Is there a way around this?

Short of going to the database and using triggers, is there an alternate path to let my Java code set the updated_on timestamp?

Thanks for the advice!

Code snippets follow.

Entity fields:

@Column(name = "updated_on")
@Temporal(TemporalType.TIMESTAMP)
private Date updatedOn;
@Column(name = "created_on")
@Temporal(TemporalType.TIMESTAMP)
private Date createdOn;

Annotated update methods:

@PreUpdate
public void setUpdatedOn(Timestamped object) {
    object.setUpdatedOn(new Date());
}

@PrePersist
public void setCreatedOn(Timestamped object) {
    if (object.getCreatedOn()==null) {
      object.setCreatedOn(new Date());
    }
}
like image 554
Freiheit Avatar asked Dec 09 '09 22:12

Freiheit


2 Answers

The link you provide describes exactly your situation: for the dirty check, updated fields are detected before the @PreUpdate method is called and changes in the @PreUpdate method are not detected any more. This is probably done for performance reasons because dirty checks can be very expensive on large object graphs. It seems right now your choices are to use a provider-specific mechanism (DescriptorEvent) or to switch to Hibernate.

like image 98
FelixM Avatar answered Oct 21 '22 15:10

FelixM


Mybe a bit late, but for completeness of information this is NOT a bug, but a documented behavior:

Date or Calendar types are assumed NOT to be mutable by default, if it is desired to call the set methods on the Date or Calendar, then the mapping must be set to be @Mutable.

For Date and Calendar types the global persistence property "eclipselink.temporal.mutable" can also be set to "true".

so, either annotate

@Mutable
@Column(name = "updated_on")
@Temporal(TemporalType.TIMESTAMP)
private Date updatedOn;

or define

<property name="eclipselink.temporal.mutable" value="true" />

in persistence.xml

like image 5
Michele Mariotti Avatar answered Oct 21 '22 14:10

Michele Mariotti