Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA/Hibernate preUpdate doesn't update parent object

In my application I defined following classes:

@Entity
@Table(name = "forums")
public class Forum {
    @Id
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid", strategy = "uuid")
    private String id;

    private String name;
    private Date lastActivity;

    @OneToMany(mappedBy = "forum", cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE })
    private List<Post> posts;

@Entity
@Table(name = "posts")
public class Post {
    @Id
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid", strategy = "uuid")
    private String id;

    private String username;
    private String content;
    private Date creationDate;

    @ManyToOne(optional = false, cascade = { CascadeType.MERGE, CascadeType.PERSIST })
    private Forum forum;

    public Post() {
        creationDate = new Date();
    }

    @PrePersist
    private void onPersist() {
        System.out.println(getClass().getName() + ": onPersist");
        if (creationDate == null) {
            creationDate = new Date();
        }

        forum.setLastActivity(creationDate);
    }

    @PreUpdate
    private void onUpdate() {
        forum.setLastActivity(new Date());
    }

If I try adding new posts to forum entity, lastActivity field is correctly updated in database by @PrePersist callback. But if I try to update post entity using following code:

  entityManager.getTransaction().begin();
  Post post = entityManager.find(Post.class, "postId");
  post.setContent("New post text");
  entityManager.merge(post);
  entityManager.getTransaction().commit();

only post data are updated and lastActivity field value doesn't change. In my opinion @PreUpdate method should do the trick and update Forum entity. Is this a bug or am I missing something?

like image 580
lhanusiak Avatar asked Oct 13 '11 11:10

lhanusiak


1 Answers

It is not bug, even that with a fast try this worked for me way you expected. Negative news is that it is not guaranteed to work, because of:

From page 93 in JPA 2.0 specification:

In general, the lifecycle method of a portable application should not invoke EntityManager or Query operations, access other entity instances, or modify relationships within the same persistence context.[43] A lifecycle callback method may modify the non-relationship state of the entity on which it is invoked.

And page 95:

It is implementation-dependent as to whether callback methods are invoked before or after the cascading of the lifecycle events to related entities. Applications should not depend on this ordering.

like image 67
Mikko Maunu Avatar answered Oct 26 '22 23:10

Mikko Maunu