Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
306 views
in Technique[技术] by (71.8m points)

java - 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());
    }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...