JPA mappedBy and JoinColumn
In database we have a foreign key. In simple foreign key establish the relationship between two database tables. Primary key of one table is placed into another table. That key is called foreign key. Here can have a book table and author table . Every author is linked with those books which are written by him. So inside the book there is author name. that reflect the relation. In relationship database model. Author is identified by his unique identification, This is the primary key of author table.
Book table will contain the identification of author. Book table have author id and this foreign key is not unique in book table. One single author can write multiple books,
@JoinColumn specifies the foreign key column is the Book table that links to the Author entity. In this case, it's author_id.
An example of how to use @JoinColumn
annotation with @ManyToOne
and @OneToMany
relationships in JPA.
Consider two entities Author
and Book
, where an author can have many books, but a book can only have one author. Here is an example of how to use @JoinColumn
with @ManyToOne
and @OneToMany
annotations: Below is Author POJO. Author.java has mappedBy = "author" annotation for
private <List> Book books
when you have a bi-directional relationship between two entities and you try to serialize them to JSON, it can lead to an infinite loop or excessive data being included in the output JSON because both entities reference each other. To prevent this issue, you can use @JsonIgnore
to instruct Jackson to ignore one side of the relationship during JSON serialization.
Author Repository
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.test.again.demoAgain.dto.Author;
@Repository
public interface AuthorRepository extends JpaRepository<Author, Long>{
}
BookRepository
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.test.again.demoAgain.dto.Book;
@Repository
public interface BookRepository extends JpaRepository<Book, Long>{
}
Author Entity class
import java.util.List;
import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.OneToMany;
@Entity
public class Author {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long author_id;
private String authorName;
public Author() {}
public Author(Long author_id,String authorName, List<Book> books) {
super();
this.author_id =author_id;
this.authorName = authorName;
this.books = books;
}
@OneToMany(mappedBy = "author", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JsonIgnore
private List<Book> books;
public Long getAuthor_id() {
return author_id;
}
public void setAuthor_id(Long author_id) {
this.author_id = author_id;
}
public String getAuthorName() {
return authorName;
}
public void setAuthorName(String authorName) {
this.authorName = authorName;
}
public List<Book> getBooks() {
return books;
}
public void setBooks(List<Book> books) {
this.books = books;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((authorName == null) ? 0 : authorName.hashCode());
result = prime * result + ((books == null) ? 0 : books.hashCode());
result = prime * result + ((author_id == null) ? 0 : author_id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Author other = (Author) obj;
if (authorName == null) {
if (other.authorName != null)
return false;
} else if (!authorName.equals(other.authorName))
return false;
if (books == null) {
if (other.books != null)
return false;
} else if (!books.equals(other.books))
return false;
if (author_id == null) {
if (other.author_id != null)
return false;
} else if (!author_id.equals(other.author_id))
return false;
return true;
}
}
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
@Entity
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long book_id;
private String title;
@ManyToOne
@JoinColumn(name = "author_id", referencedColumnName = "author_id")
private Author author;
public Long getBook_id() {
return book_id;
}
public void setBook_id(Long book_id) {
this.book_id = book_id;
}
public Book() {
super();
// TODO Auto-generated constructor stub
}
public Book(Long book_id, String title, Author author) {
super();
this.book_id = book_id;
this.title = title;
this.author = author;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Author getAuthor() {
return author;
}
public void setAuthor(Author author) {
this.author = author;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((author == null) ? 0 : author.hashCode());
result = prime * result + ((book_id == null) ? 0 : book_id.hashCode());
result = prime * result + ((title == null) ? 0 : title.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Book other = (Book) obj;
if (author == null) {
if (other.author != null)
return false;
} else if (!author.equals(other.author))
return false;
if (book_id == null) {
if (other.book_id != null)
return false;
} else if (!book_id.equals(other.book_id))
return false;
if (title == null) {
if (other.title != null)
return false;
} else if (!title.equals(other.title))
return false;
return true;
}
// getters and setters
}
In the Author
entity, we have a one-to-many relationship with the Book
entity, which means that an author can have many books. We use the mappedBy
attribute to map this relationship to the author
field in the Book
entity.
In the Book
entity, we have a many-to-one relationship with the Author
entity, which means that a book can only have one author. We use the @ManyToOne
annotation to specify this relationship, and the @JoinColumn
annotation to specify the name of the foreign key column (author_id
) and the referenced column (id
) in the Author
table.
When we fetch a Book
entity, its associated Author
entity is loaded lazily (i.e., only when it is accessed), because we specified fetch = FetchType.LAZY
in the @ManyToOne
annotation. If we want to load the Author
entity eagerly (i.e., at the same time as the Book
entity), we can use fetch = FetchType.EAGER
instead.
Similarly, we can use @JoinColumn
with @OneToMany
annotations as well to specify the name of the foreign key column and the referenced column in the other table.
Service class for Book. BookService.java component BookService.java is referred form controller class or REST controller component. BookService.java is autowired in BookController class.
BookService class
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import com.test.again.demoAgain.dto.Author;
import com.test.again.demoAgain.dto.Book;
import com.test.again.demoAgain.repo.AuthorRepository;
import com.test.again.demoAgain.repo.BookRepository;
@Service
public class BookService {
@Autowired
private BookRepository repo;
@Autowired
private AuthorRepository authorRepo;
//Optional
public Book findById(Long id) {
return repo.findById(id).get();
}
public void deleteById(Long id) {
repo.deleteById(id);
}
public List<Book> getAllBook(){
return repo.findAll();
}
public ResponseEntity<Book> saveBook(Book obj) {
Author author = authorRepo.findById(obj.getAuthor().getAuthor_id()).orElse(null);
System.out.println("received data " + obj);
obj.setAuthor(author);
Book book = repo.save(obj);
return new ResponseEntity<>(book, HttpStatus.OK);
}
public Boolean existsById(Long id ) {
return repo.existsById(id);
}
public ResponseEntity<String> sayHello() {
return ResponseEntity.ok("Hello, World!");
}
}
Here is Book Controller.java. This class has a method annotated with @PostMapping("/save")
BookController class
import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.test.again.demoAgain.dto.Book; import com.test.again.demoAgain.service.BookService; @RestController @RequestMapping("/api/book") public class BookController { @Autowired BookService service; @PostMapping("/save") public ResponseEntity<Book> saveBook(@RequestBody Book book) { return service.saveBook(book); } @GetMapping("/getAll") public List<Book> getAllBook() { return service.getAllBook(); } }
first call the save author end point URL may be like this. http://localhost:8989/api/author/save from postman. you can use this. No need to provide author_id. JPA is generating the unique primary key for in this case. We need to pass "authorName" only.
once you have called the save operation REST service of author. then you can save the book having the author_id. final end point URL may be like this. http://localhost:8989/api/book/save from postman. you can use this.
Thank You !!!!
Comments
Post a Comment