What are the different ways to delete a child entity in JPA/hibernate through Spring Data?

Let’s say you have an application which creates blog posts and saves them and also the comments user enter on the posts.

The Blogpost and the comment represent a parent and child relationship.

You may want to delete the comments in three different ways:

  1. Delete the comment whenever the blogpost is deleted.
  2. Delete the comment separately without deleting the blogpost.
  3. Delete the comment whenever the comment is just removed from the blogpost.

Let’s look at how to implement all these scenarios.

Here are the entity objects:

Blogpost:

package com.hibernate.childrecords;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
public class Blogpost {



    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    private String title;

    @OneToMany
    List<Comment> commentList = new ArrayList<>();


    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public List<Comment> getCommentList() {
        return commentList;
    }

    public void setCommentList(List<Comment> commentList) {
        this.commentList = commentList;
    }

    @Override
    public String toString() {
        return "Blogpost{" +
                "id=" + id +
                " title=" + title +


                '}';
    }
}

Comment:

package com.hibernate.childrecords;

import javax.persistence.*;

@Entity
public class Comment {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    private String message;

    @ManyToOne
    private Blogpost blogpost;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Blogpost getBlogpost() {
        return blogpost;
    }

    public void setBlogpost(Blogpost blogpost) {
        this.blogpost = blogpost;
    }

    @Override
    public String toString() {
        return "Comment{" +
                "id=" + id +
                "comment=" + message +
                '}';
    }
}

And the repositories provided by Spring Data which provide a higher level of abstraction and removes the need to manually write code to perform CRUD operations:

Blog repository:

package com.hibernate.childrecords;

import org.springframework.data.repository.CrudRepository;

public interface BlogRepository extends CrudRepository<Blogpost,Long> {
}

Comment repository:

package com.hibernate.childrecords;

import org.springframework.data.repository.CrudRepository;

public interface CommentRepository extends CrudRepository<Comment,Long> {
}

Let’s dive into scenario 1:

Delete the comment whenever the blogpost is deleted.

Let’s first set the cascade relationship between Blogpost and Comment.

Let’ set it to CascadeType.ALL to make it easier for saving and removing parent and child records:

Now whenever a blogpost is saved the comments added to it are also saved to the database. You need not save the comment objects separately.

Similarly when a blogpost is deleted all its comments are deleted from database automatically.

Here is the code:

Let’s create a sample blogpost and comment:

        Blogpost post = new Blogpost();
        post.setTitle("First post");

        Comment comment = new Comment();
        comment.setMessage("My first comment");
        comment.setBlogpost(post);

        post.getCommentList().add(comment);
        blogRepository.save(post);

The above code saves a blogpost entity and its comment to database.

Now let’s display them using the below method:

private void display() {

        System.out.println("Displaying records..");
        Iterable<Blogpost> blogpostList = blogRepository.findAll();


        for (Blogpost blogpost : blogpostList) {

            System.out.println(blogpost);
        }


        Iterable<Comment> comments
                = commentRepository.findAll();


        for (Comment comment1 : comments) {

            System.out.println(comment1);
        }
    }

Below is the output:

Displaying records..
Blogpost{id=1 title=First post}
Comment{id=2comment=My first comment}

Now let’s delete the blogpost using the single line of code below:

        blogRepository.delete(post);

And now when you display the records , you don’t get either the blogpost or the comment objects.

That was pretty straight forward

Now let’s check the second scenario:

Delete the comment separately without deleting the blogpost.

Let’s say you just want to remove a comment from database without deleting the blogpost.

To do this , you need to follow the below steps:

Step 1 : Remove the comment from the blogpost object

Step 2 : Save the blogpost object

Step 3: Finally delete the comment object

Below is the code :

        post.getCommentList().remove(comment);

        blogRepository.save(post);

        commentRepository.delete(comment);

In case if you don’t follow the first two steps you will get constraint violation exceptions as the blogpost is still having an association with the comment.

Now if you display the records , you will see the blogpost record but not the comment record:

Displaying records..
Blogpost{id=1 title=First post}

That was a little complex than the first scenario.

Now let’s look into the third scenario:

Delete the comment whenever the comment is just removed from the blogpost

In this scenario you want to delete the comment from the database whenever its association is removed from the blogpost because it doesn’t make sense to keep a comment in the system when it is no longer associated with its original post.

To do this , you need to set the attribute orphanRemoval = true at the @OneToMany annotation in the blogpost entity:

To implement this , you need to follow two steps:

Step 1: Remove the comment object from the blogpost object

Step 2: Save the blogpost object:

    post.getCommentList().remove(comment);
    blogRepository.save(post);

Those two lines of code will delete the comment automatically from the database.

Now if you display the records you will only get the blogpost object as in the previous case:

Displaying records..
Blogpost{id=1 title=First post}

That’s it!


Posted

in

, ,

by

Comments

Leave a Reply

Discover more from The Full Stack Developer

Subscribe now to keep reading and get access to the full archive.

Continue reading