Books
Objective: Apply JPA annotations to map Java classes to database tables and understand entity lifecycle.
Set Up a Java Project:
- Create a new Maven project. Use JPA starter if needed.
Define the
Book
Entity:- Create a simple entity class called
Book
with the following attributes:id
(primary key)title
author
isbn
(must be unique)publishedYear
- Use JPA annotations to map the entity class to a database table named
books
. - Ensure the
isbn
field is unique. - Include a no-arg constructor (
@NoArgsConstructor
). - Add Lombok annotations like
@Getter
,@Setter
,@ToString
, and@Builder
.
- Create a simple entity class called
Add JPA Annotations:
- Use
@Entity
,@Table
,@Id
,@GeneratedValue
, and@Column
to define the primary key and attribute mappings.
- Use
Set Up the
Main
Class:Add a static property:
EntityManagerFactory
.Create methods for CRUD operations in a
BookDAO
class:public static void createBook(Book book)
- This method persists a new book to the database.
public static Book readBook(int id)
- This method retrieves a book by ID.
public static Book updateBook(Book updatedBook)
- This method updates an existing book.
public static void deleteBook(int id)
- This method deletes a book by ID.
public static List<Book> readAllBooks()
- This method retrieves all books from the database using a
TypedQuery
.
- This method retrieves all books from the database using a
Use
try-with-resources
orfinally
blocks to properly closeEntityManager
objects.Add JPA Entity Lifecycle Comments
- Add comments explaining when an entity is in:
- Transient State (before persist)
- Managed State (after persist)
- Detached State (after transaction commit)
- Removed State (before deletion)
Example:
public static void main(String[] args) { // Entity is in transient state Book book = new Book("Effective Java", "Joshua Bloch", "9780134685991", 2018); } public static void createBook(Book book) { try (EntityManager em = emf.createEntityManager()) { em.getTransaction().begin(); // Entity is in managed state after persist() em.persist(book); // Entity becomes detached after transaction is committed em.getTransaction().commit(); } }
- Add comments explaining when an entity is in:
Validate ISBN Before Persisting a Book
- Add a method in the
Book
class to verify that the ISBN is valid. - Use
@PrePersist
to validate ISBN before saving a book. - If ISBN is invalid, throw an exception.
- Add a
@PreUpdate
method to validate ISBN before updating. - Hint: Use the
ISBNValidator
class from the ISBN validation exercise
- Add a method in the
Create a Test Class
- Add a test class that contains a test method for each CRUD operation. It’s not an integration test, but just a sort of
main
method that calls each method in theBookDAO
class.
- Add a test class that contains a test method for each CRUD operation. It’s not an integration test, but just a sort of
Populate the Database with Books
- Add 10 books to the database
- At least 3 books should be authored by “J.K. Rowling”
- At least 4 books should be authored by “George Orwell”
- The oldest book should be from 1945
- The most recent book should be from 2024
Aggregate Data with Queries
- Calculate the average publication year of all books
- Find the average publication year of books authored by “George Orwell”
- Count how many books are authored by “J.K. Rowling”
- Find the title of the oldest book** in the database.
- Retrieve the most recently published book
- Sum the publication years of all books
classDiagram direction LR class Book { - int id - String title - String author - String isbn - int publishedYear - void prePersist() - void preUpdate() - boolean isValidIsbn(String isbn) } class BookDAO { + Book createBook(Book book) + Book readBook(int id) + Book updateBook(Book updatedBook) + boolean deleteBook(int id) + List~Book~ readAllBooks() + double averagePublicationYear() + double averagePublicationYearByAuthor(String author) + long countByAuthor(String author) + String findOldestTitle() + Book findMostRecent() + int sumPublicationYears() } class Main { -EntityManagerFactory emf +void main(String[] args) } class ISBNValidator { +boolean isValid(String isbn) } BookDAO --> Book : manages Main --> BookDAO : uses Main --> Book : uses Book ..> ISBNValidator : validates ISBN
- Why do we need a no-arg constructor in an entity class?
- Investigate where in the code we can:
- Specify the database dialect?
- Define JDBC connection properties?
- Add annotated classes?
- What is the purpose of
@GeneratedValue
?- What are the different primary key generation strategies in JPA?
- What is
try-with-resources
, and how can we use it in JPA? - What is the difference between
persist()
andmerge()
in JPA? - What is the difference between
TypedQuery
andQuery
? - What is the difference between
getSingleResult()
andgetResultList()
? - What are the different states of an entity in JPA?