I am working on a small project using Spring Boot, Hibernate, and JPA. I have created three entities-
- Book
- Author
- Publication
Required relationships-
- One book can be written by multiple authors and the author can have many books. Therefore- Many to Many Relationship
- One book can have only one publication and one publication can have many books. Therefore- Many to One Relationship
The code for these entities-
- Book.java-
//...import statements
@Entity
@Data
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "Book_id")
private int id;
@Column(name = "Book_name",nullable = false, unique = true)
private String bookName;
@Column(name = "Publication_date",nullable = false)
@JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd")
private Date publishDate;
@Column(name = "ISBN",nullable = false, unique = true)
private String isbn;
@ManyToOne
@JoinColumn(name = "publication_id", nullable = false)
private Publication publication;
@ManyToMany
@JoinTable(name = "Book_Author", joinColumns = @JoinColumn(name = "book_id", referencedColumnName = "Book_id"), inverseJoinColumns = @JoinColumn(name = "author_id", referencedColumnName = "Author_id"))
private Set<Author> authors = new HashSet<>();
}
- Author.java-
//... import statements
@Entity
@Data
public class Author {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="Author_id")
private int id;
@Column(name="First_name",nullable = false)
private String firstName;
@Column(name="Last_name",nullable = false)
private String lastName;
@Column(name="Mobile_number",nullable = false, unique = true,length = 10)
private long mobileNo;
@ManyToMany(mappedBy = "authors")
Set<Book> books=new HashSet<>();
}
- Publication.java-
//... import statements
@Entity
@Data
public class Publication {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(name="Publication_name",nullable = false,unique = true)
private String name;
@Column(name="Registration_number",nullable = false, unique = true)
private String regNumber;
@OneToMany(mappedBy = "publication")
Set<Book> books=new HashSet<>();
}
Problems- I am facing following issues with the code:
- In the Many to Many relationship of Book and Author, when fetching Book or Author, I do not get the corresponding Author and Book respectively. What I get is an empty set. Example-
@Override
public BookDto getBook(int id) {
Book book=this.bookRepository.findById(id).get();
System.out.println("Book Publisher: "+book.getPublication());
System.out.println("Author: "+book.getAuthors()); //empty set
return this.bookToDto(book);
}
Although, when I use SQL query in MySQL, I get the result-
Select * from demodb.book natural join demodb.book_author natural join demodb.author
Also, the Hibernate query shows that the query is being fired on the join of the tables to fetch data but nothing is returned in the query.
2. In the Many to One relationship of Book and Publication, when fetching Publication, the associated set of books is not fetched from the database, although Hibernate query is fired to fetch. But, when fetching a book, publication is fetched.
Query when fetching publication by id- (I am aware that cyclic dependency might occur but the objects are not fetched at all because I get empty Set in publication.getBooks())
Hibernate:
select
p1_0.id,
p1_0.publication_name,
p1_0.registration_number
from
publication p1_0
where
p1_0.id=?
Hibernate:
select
b1_0.publication_id,
b1_0.book_id,
b1_0.book_name,
b1_0.isbn,
b1_0.publication_date
from
book b1_0
where
b1_0.publication_id=?
Hibernate:
select
b1_0.publication_id,
b1_0.book_id,
b1_0.book_name,
b1_0.isbn,
b1_0.publication_date
from
book b1_0
where
b1_0.publication_id=?
Hibernate:
select
a1_0.book_id,
a1_1.author_id,
a1_1.first_name,
a1_1.last_name,
a1_1.mobile_number
from
book_author a1_0
join
author a1_1
on a1_1.author_id=a1_0.author_id
where
a1_0.book_id=?
Hibernate:
select
b1_0.author_id,
b1_1.book_id,
b1_1.book_name,
b1_1.isbn,
p1_0.id,
p1_0.publication_name,
p1_0.registration_number,
b1_1.publication_date
from
book_author b1_0
join
book b1_1
on b1_1.book_id=b1_0.book_id
left join
publication p1_0
on p1_0.id=b1_1.publication_id
where
b1_0.author_id=?
Hibernate:
select
a1_0.book_id,
a1_1.author_id,
a1_1.first_name,
a1_1.last_name,
a1_1.mobile_number
from
book_author a1_0
join
book b1_1
on b1_1.book_id=b1_0.book_id
left join
publication p1_0
on p1_0.id=b1_1.publication_id
where
b1_0.author_id=?
- Error in using FetchType.LAZY in book-publication relationship-
When I use fetch=FetchType.LAZY on the publication in Book entity and try to fetch book,
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "publication_id", nullable = false)
private Publication publication;
I get the following error-
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.ayushsingh.demojpa.dto.BookDto["publication"]->com.ayushsingh.demojpa.entity.Publication$HibernateProxy$F4hnTR8H["hibernateLazyInitializer"])
Note-
I am using ModelMapper 3.1.1, Dev Tools, Java version- 17 and Spring Boot Version- 3.0.6 .
I have clubbed these issues as they might be releated. Please help.