How to use @PrePersist and @PreUpdate on Embeddable with JPA and Hibernate

How to use @PrePersist and @PreUpdate on Embeddable with JPA and Hibernate
Techiio-author
Written by Sagar RabidasFebruary 24, 2022
10 min read
Hibernate
2 VIEWS 0 LIKES 0 DISLIKES SHARE
0 LIKES 0 DISLIKES 2 VIEWS SHARE
Techiio-author
Sagar Rabidas

Software Developer

How to use @PrePersist and @PreUpdate on Embeddable with JPA and Hibernate - Let's start the discussion

In this example, you will learn how to map components using Hibernate Annotations. Consider the following relationship between Student and Address entity.

In this tutorial, we'll see how we can map one entity that contains embedded properties to a single database table. So, for this purpose, we'll use the @Embeddable and @Embedded annotations provided by the JPA.

How to use @PrePersist and @PreUpdate:

Hibernate ORM 5.2.17 now allows you to use the @prepersist and @preupdate JPA entity listeners, we can simplify the previous example, as you may see in this article.

Domain Model:-

We want to encapsulate the audit logic in the Audit embeddable type:

@Embeddable
public class Audit {
 
    @Column(name = "created_on")
    private LocalDateTime createdOn;
 
    @Column(name = "created_by")
    private String createdBy;
     
    @Column(name = "updated_on")
    private LocalDateTime updatedOn;
 
    @Column(name = "updated_by")
    private String updatedBy;
 
    @PrePersist
    public void prePersist() {
        createdOn = LocalDateTime.now();
        createdBy = LoggedUser.get();
    }
 
    @PreUpdate
    public void preUpdate() {
        updatedOn = LocalDateTime.now();
        updatedBy = LoggedUser.get();
    }
 
    //Getters and setters omitted for brevity
}

The JPA entities will use the Audit embeddable type as follows:

@Entity(name = "Post")
@Table(name = "post")
public class Post {
 
    @Id
    private Long id;
 
    private String title;
     
    @Embedded
    private Audit audit = new Audit();
 
    @ManyToMany
    @JoinTable(
        name = "post_tag",
        joinColumns = @JoinColumn(name = "post_id"),
        inverseJoinColumns = @JoinColumn(name = "tag_id")
    )
    private List<Tag> tags = new ArrayList<>();
 
    //Getters and setters omitted for brevity
}
 
@Entity(name = "Tag")
@Table(name = "tag")
public class Tag {
 
    @Id
    private String name;
 
    @Embedded
    private Audit audit = new Audit();
 
    //Getters and setters omitted for brevity
}

Testing time:-

Now, when inserting 3 Tag entities:

Tag jdbc = new Tag();
jdbc.setName("JDBC");
entityManager.persist(jdbc);
 
Tag hibernate = new Tag();
hibernate.setName("Hibernate");
entityManager.persist(hibernate);
 
Tag jOOQ = new Tag();
jOOQ.setName("jOOQ");
entityManager.persist(jOOQ);

Hibernate properly sets the created_on and created_by columns on the associated tag rows:

INSERT INTO tag (
    created_by,
    created_on,
    updated_by,
    updated_on,
    name
)
VALUES (
    'Alice',
    '2018-05-02 09:56:54.939',
    NULL(VARCHAR),
    NULL(TIMESTAMP),
    'JDBC'
)
 
INSERT INTO tag (
    created_by,
    created_on,
    updated_by,
    updated_on,
    name
)
VALUES (
    'Alice',
    '2018-05-02 09:56:54.955',
    NULL(VARCHAR),
    NULL(TIMESTAMP),
    'Hibernate'
)
 
INSERT INTO tag (
    created_by,
    created_on,
    updated_by,
    updated_on,
    name
)
VALUES (
    'Alice',
    '2018-05-02 09:56:54.955',
    NULL(VARCHAR),
    NULL(TIMESTAMP),
    'jOOQ'
)

The same goes for the Post entity:

Post post = new Post();
post.setId(1L);
post.setTitle(
    "High-Performance Java Persistence, 1st Edition
");
 
post.getTags().add(
    entityManager.find(Tag.class, "JDBC")
);
post.getTags().add(
    entityManager.find(Tag.class, "Hibernate")
);
post.getTags().add(
    entityManager.find(Tag.class, "jOOQ")
);
 
entityManager.persist(post);

Hibernate generates the following INSERT statements:

INSERT INTO post (
    created_by,
    created_on,
    updated_by,
    updated_on,
    title,
    id
)
VALUES (
    'Alice',
    '2018-05-02 09:56:55.046',
    NULL(VARCHAR),
    NULL(TIMESTAMP),
    'High-Performance Java Persistence, 1st Edition',
    1
)
 
INSERT INTO post_tag (post_id, tag_id) VALUES (1, 'JDBC')
INSERT INTO post_tag (post_id, tag_id) VALUES (1, 'Hibernate')
INSERT INTO post_tag (post_id, tag_id) VALUES (1, 'jOOQ')

When updating the Post entity:

Post post = entityManager.find(Post.class, 1L);
 
post.setTitle(
    "High-Performance Java Persistence, 2nd Edition"
);

The updated_on and update_by columns will be set by the @PreUpdate event listener on the embeddable type:

UPDATE
    post
SET
    created_by = 'Alice',
    created_on = '2018-05-02 09:56:55.046',
    updated_by = 'Alice',
    updated_on = '2018-05-02 09:56:55.106',
    title = 'High-Performance Java Persistence, 2nd Edition'
WHERE
    id = 1

Conclusion:-

So, even as previously, you could gain the same purpose the usage of an @entitylistener, now you apply the @prepersist and @preupdate event listeners son the embeddable type, consequently simplifying the implementation.

Hibernate
PrePersist
JPA
Java
2 VIEWS 0 LIKES 0 DISLIKES SHARE
0 LIKES 0 DISLIKES 2 VIEWS SHARE
Was this blog helpful?
techiio-price-plantechiio-price-plantechiio-price-plantechiio-price-plantechiio-price-plan
You must be Logged in to comment
Code Block
Techiio-author
Sagar Rabidas
Software Developer
Techiio-followerTechiio-followerTechiio-followerTechiio-followerTechiio-follower
+8 more
300 Blog Posts
14 Discussion Threads
Trending Technologies
15
Software40
DevOps46
Frontend Development24
Backend Development20
Server Administration17
Linux Administration26
Data Center24
Sentry24
Terraform23
Ansible83
Docker70
Penetration Testing16
Kubernetes21
NGINX20
JenkinsX17
Techiio-logo

Techiio is on the journey to build an ocean of technical knowledge, scouring the emerging stars in process and proffering them to the corporate world.

Follow us on:

Subscribe to get latest updates

You can unsubscribe anytime from getting updates from us
Developed and maintained by Wikiance
Developed and maintained by Wikiance