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
BookEntity:- Create a simple entity class called
Bookwith the following attributes:id(primary key)titleauthorisbn(must be unique)publishedYear
- Use JPA annotations to map the entity class to a database table named
books. - Ensure the
isbnfield 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@Columnto define the primary key and attribute mappings.
- Use
Set Up the
MainClass:Add a static property:
EntityManagerFactory.Create methods for CRUD operations in a
BookDAOclass: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-resourcesorfinallyblocks to properly closeEntityManagerobjects.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
Bookclass to verify that the ISBN is valid. - Use
@PrePersistto validate ISBN before saving a book. - If ISBN is invalid, throw an exception.
- Add a
@PreUpdatemethod to validate ISBN before updating. - Hint: Use the
ISBNValidatorclass 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
mainmethod that calls each method in theBookDAOclass.
- 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
TypedQueryandQuery? - What is the difference between
getSingleResult()andgetResultList()? - What are the different states of an entity in JPA?
