views:

655

answers:

1

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: http://www.eclipse.org/forums/index.php?t=msg&goto=499756&S=3bcc64b0e0822e7707f2ce0b616d92df

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 EnttityListener 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());
    }
}
+1  A: 

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.

FelixM
Felix - Thank you for the clarification. I thought thats what I was seeing.I see how to implement the DescriptorEvent handling, almost as easy as annotating a few methods. Just gotta find the right XML file to add the handler.Thanks again!
Freiheit