Hasebul Hassan Chowdhury
Posted on November 30, 2024
What is a bidirectional relationship in relational database model? let's take a quick look -
Suppose you two table Post and Post_Comment. Now you want to find out which comment are associated with which post or for a post how many comments are associated with that? How you can do that?
Here is the basic Post entity table
@Entity
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column
private String title;
public Post() {
}
// ignoring setter and getter
}
Here is the basic Post comment entity table
@Entity
public class PostComment {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
@Column
private String description;
public PostComment() {
}
// ignoring setter and getter
Currently, both table/entity don't have any relationship between them.
Now let's try to construct a unidirectional relationship between post and post comment.
Here are a few cases to keep in mind :-
- Post can be owner side (one-To-Many)
- Post Comment can be owner side (Many-To-One)
First, let's define Case 1 :
@Entity
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column
private String title;
@OneToMany(cascade = CascadeType.PERSIST, orphanRemoval = true)
private List<PostComment> postComments = new ArrayList<>();
public Post() {
}
public void addComment(PostComment comment) {
postComments.add(comment);
}
public void removeComment(PostComment comment) {
postComments.remove(comment);
}
// ignoring setter and getter
}
Now what we have done here?
We added a list and telling Post that it can have zero, one or more than one post comment by using @OneToMany
. There can be mutiple comment associated with a single Post. we are cascade = CascadeType.PERSIST, orphanRemoval = true
in these two later.
@OneToMany(cascade = CascadeType.PERSIST, orphanRemoval = true)
private List<PostComment> postComments = new ArrayList<>();
we also added two method which will make our life easier to add/remove comment
public void addComment(PostComment comment) {
postComments.add(comment);
}
public void removeComment(PostComment comment) {
postComments.remove(comment);
}
Okay, we are almost done with our entity design (Not fully done). Let's take a look how we can save/persist a post with a comment.
@Service
public class PostService {
@Autowired
EntityManager eManager;
@Transactional
public void addPost1() {
Post post = new Post();
post.setTitle("Hibernate in action is quite good");
PostComment comment = new PostComment();
comment.setDescription("Recommended");
post.addComment(comment);
eManager.persist(post);
}
}
Here we are creating a post and then setting the title and adding a comment. Then calling eManager.persist(post)
which will save the post and its associated comment. Easy, right!!!. Lets take a look at the database (H2) :
We can see a Post table which have only one row with id and title where id is 1 and title is "Hibernate in action is quite good".
Now lets look at post comment table :
we can see a row with id and description where id is 1 and description is Recommended.
Nice. but what is that POST_POST_COMMENTS table? We did not define any entity/table in our codebase. So here's the explanation
When we used one-to-many relationship between post and comment. Each comment will be associated with a post id. So there will be a mapping between post_id and post_comment_id. But where should we store that info? Hibernate creates another table by combining the two relational entity/table name (POST and POST_COMMENTS) where it stores two column primary id from both table. In our case, id from post table (POST_ID) and id from post comment table (POST_COMMENT_ID).
Can we improve that? An extra table is an extra burden.yes we can. lets see how we can do that?
@OneToMany(cascade = CascadeType.PERSIST, orphanRemoval = true)
@JoinColumn(name = "post_id")
private List<PostComment> postComments = new ArrayList<>();
@JoinColumn(name = "post_id")
This join column annotation tells that we don't need any extra table for mapping. Instead, POST_COMMENT table will handle it. There will be an extra column named "post_id" in POST_COMMENT table, which will store the associated post id for that comment, but good things is JPA/hibernate will do that on its own. We don't need to change our post comment entity.
lets add another comment in post with id 1.
@Transactional
public void addCommentOnPost() {
Post post = eManager.find(Post.class, 1);
PostComment comment = new PostComment();
comment.setDescription("this book is also for beginner");
post.addComment(comment);
eManager.persist(post);
}
Now lets try to fetch those comments.
@Transactional
public void findCommentByPostId() {
Post post = eManager.find(Post.class, 1);
System.out.println("Number of comment " + post.getPostComments().size());
System.out.println(post.getPostComments());
}
/*
Number of comment 2
[
PostComment [id=1, description=Recommended],
PostComment [id=2, description=this book is also for beginner]
]
*/
jpa/hibernate will go to POST_COMMENT table and check on post_id if there is a match in our case post_id = 1. it will pick them up.
Posted on November 30, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.