Popular Searches
Popular Course Categories
Popular Courses

Creating JPA Entities and Repository Interfaces

Creating JPA Entities and Repository Interfaces

Spring Data JPA and Database Integration

Creating JPA Entities and Repository Interfaces

Course: Advanced Java Training

Topic: Creating JPA Entities and Repository Interfaces

Course Link: Advanced Java Training Course

Demo Link: Register for a Course Demo

Website: JustAcademy


1. Introduction to JPA Entities and Repository Interfaces

Java Persistence API (JPA) is a Java specification that defines how Java objects are mapped to relational database tables and how persistent data is managed. In modern Spring Boot applications, JPA is commonly used with Hibernate, an implementation of the JPA specification, and Spring Data JPA, which simplifies database access through repository interfaces.

A JPA entity is a Java class that represents persistent data, such as a student, employee, product, or order. A repository interface defines the operations used to save, retrieve, update, and delete these entities without requiring developers to write repetitive database-access code for every operation.

For example, a Student entity can represent a row in a database table named students. A StudentRepository can provide methods to save a student, retrieve a student by ID, search by email, and delete a student.

Learning Objectives

  • Understand JPA entities and their relationship with database tables.
  • Learn how to create entity classes using JPA annotations.
  • Configure primary keys and generated identifiers.
  • Understand entity fields, constructors, getters, and setters.
  • Create repository interfaces using Spring Data JPA.
  • Use built-in CRUD methods and derived query methods.
  • Understand custom queries, pagination, sorting, and transactions.
  • Apply entity and repository best practices in Spring Boot projects.

2. What Is a JPA Entity?

A JPA entity is a regular Java class that is mapped to a database table. Each entity object represents a persistent record, and its mapped fields represent database columns.

For example, an Employee entity may contain an ID, employee name, email address, and salary. When the entity is persisted, JPA and its provider translate the entity state into database operations.

Example Entity

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

@Entity
@Table(name = "employees")
public class Employee {

    @Id
    private Long id;

    private String name;
    private String email;

    public Employee() {
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

This example defines an entity mapped to the employees table. The @Id annotation identifies the primary key. Because the example does not configure automatic ID generation, an identifier must be assigned by the application or another appropriate mechanism.

3. Important JPA Entity Annotations

JPA provides annotations that define how Java classes and fields map to database tables and columns.

Annotation Purpose Example
@Entity Marks a class as a JPA entity. @Entity
@Table Specifies the database table name and optional table metadata. @Table(name = "students")
@Id Identifies the primary-key field. @Id
@GeneratedValue Configures primary-key generation. @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column Configures a mapped column's name and constraints. @Column(nullable = false)
@Transient Excludes a field from persistence mapping. @Transient
@Enumerated Maps an enum value to a database representation. @Enumerated(EnumType.STRING)
@Temporal Legacy annotation for certain java.util.Date and Calendar mappings. Generally unnecessary with modern Java date/time types.
@Version Supports optimistic locking to detect conflicting updates. @Version

In Spring Boot 3 and later, JPA imports generally use the jakarta.persistence package. Older Spring Boot 2 projects commonly use javax.persistence. Use the namespace appropriate to the project's Spring Boot and JPA versions.

4. Understanding the @Entity Annotation

The @Entity annotation tells the JPA provider that a class should be managed as a persistent entity. The class must meet JPA entity requirements, including having a primary key and a public or protected no-argument constructor.

import jakarta.persistence.Entity;
import jakarta.persistence.Id;

@Entity
public class Department {

    @Id
    private Long id;

    private String departmentName;

    protected Department() {
    }

    public Department(Long id, String departmentName) {
        this.id = id;
        this.departmentName = departmentName;
    }
}

If no table name is specified with @Table, the persistence provider applies its naming rules to determine the table name. Explicit table naming can make mappings easier to understand and maintain.

5. Mapping an Entity to a Database Table

The @Table annotation defines the database table associated with an entity. It can also specify schema names and certain database constraints.

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

@Entity
@Table(name = "students")
public class Student {

    @Id
    private Long id;

    private String name;
    private String email;

    protected Student() {
    }
}

In this example, the entity maps to the students table. The fields are mapped to columns according to the JPA provider's naming rules unless column mappings are specified explicitly.

6. Defining Primary Keys

Every JPA entity must have a primary key. The primary key uniquely identifies each persistent entity and allows the persistence provider to locate and manage its database record.

6.1 Using @Id

@Id
private Long id;

With this approach, the application or database mechanism must provide the identifier.

6.2 Using @GeneratedValue

When the database or persistence provider should generate identifiers, use @GeneratedValue with an appropriate strategy.

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@Entity
public class Product {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String productName;

    protected Product() {
    }

    public Product(String productName) {
        this.productName = productName;
    }
}

Common Identifier Strategies

Strategy Description
GenerationType.IDENTITY Uses a database identity column or equivalent generated-key mechanism.
GenerationType.SEQUENCE Uses a database sequence where supported.
GenerationType.TABLE Uses a database table to manage identifier generation.
GenerationType.AUTO Allows the persistence provider to select a suitable strategy.

Choose a strategy supported by the target database and its schema. Identity and sequence generation can behave differently, particularly when inserts are batched or database portability is important.

7. Mapping Columns with @Column

The @Column annotation configures the database column associated with a persistent field or property. It can define a column name, length, nullability, uniqueness, and other mapping options.

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

@Entity
@Table(name = "customers")
public class Customer {

    @Id
    private Long id;

    @Column(name = "full_name", nullable = false, length = 100)
    private String name;

    @Column(name = "email_address", nullable = false, unique = true, length = 150)
    private String email;

    protected Customer() {
    }
}

Explanation:

  • name defines the database column name.
  • nullable = false specifies that the mapped column should not allow SQL NULL values when schema generation applies the constraint.
  • length = 100 defines the requested length for applicable column types, such as strings.
  • unique = true requests a uniqueness constraint when the schema is generated.

Entity annotations do not automatically guarantee that an existing database schema has been updated. Use an appropriate migration or schema-management process to apply required database constraints.

8. Entity Constructors, Getters, and Setters

JPA entities commonly include a no-argument constructor, constructors for application use, and methods for accessing or updating fields. The no-argument constructor must be public or protected so the persistence provider can instantiate the entity.

@Entity
public class Course {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String title;
    private Integer durationInHours;

    protected Course() {
    }

    public Course(String title, Integer durationInHours) {
        this.title = title;
        this.durationInHours = durationInHours;
    }

    public Long getId() {
        return id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public Integer getDurationInHours() {
        return durationInHours;
    }

    public void setDurationInHours(Integer durationInHours) {
        this.durationInHours = durationInHours;
    }
}

Field access or property access is determined by where mapping annotations are placed. Be consistent with the selected access strategy. For sensitive or invariant-heavy entities, carefully control setters and expose domain-specific methods instead of allowing unrestricted state changes.

9. What Is a Repository Interface?

A repository interface provides an abstraction for data access. Spring Data JPA can generate an implementation at runtime based on the repository interface, its parent interface, and its declared query methods.

Instead of writing repetitive SQL or implementing every CRUD method manually, developers can extend JpaRepository and use the provided methods.

Example Repository

import org.springframework.data.jpa.repository.JpaRepository;

public interface StudentRepository
        extends JpaRepository<Student, Long> {
}

Here, Student is the entity type and Long is the type of its primary key. Spring Boot can discover and configure the repository when it is in a package included in repository scanning.

10. Understanding Repository Parent Interfaces

Spring Data provides several repository interfaces with different levels of functionality.

Interface Purpose Typical Use
Repository<T, ID> Marker interface for repository abstractions. Building a custom, limited repository API.
CrudRepository<T, ID> Provides common create, read, update, and delete operations. Basic persistence requirements.
PagingAndSortingRepository<T, ID> Provides pagination and sorting capabilities. Reading large datasets in manageable portions.
JpaRepository<T, ID> Adds JPA-specific repository functionality to the CRUD and paging capabilities in current Spring Data JPA versions. Typical Spring Boot applications using JPA.

The exact inherited method set depends on the Spring Data version. For most standard Spring Boot JPA applications, JpaRepository is a convenient starting point.

11. Common JpaRepository Methods

Extending JpaRepository gives the repository access to common persistence operations.

Method Description Example
save(entity) Saves a new entity or updates a persistent entity according to its state and identifier handling. repository.save(student)
findById(id) Retrieves an entity by primary key. repository.findById(1L)
findAll() Retrieves all entities. repository.findAll()
existsById(id) Checks whether an entity with the given ID exists. repository.existsById(1L)
count() Counts entities. repository.count()
delete(entity) Deletes the specified entity. repository.delete(student)
deleteById(id) Deletes the entity associated with an ID. repository.deleteById(1L)
findAll(pageable) Retrieves a page of entities. repository.findAll(pageable)

Use pagination for large tables rather than loading every record with findAll(). Also, understand the behavior of save(): it is not simply a guarantee that a SQL UPDATE statement will be executed. The persistence provider determines the database operations based on entity state and mapping.

12. Creating a Spring Boot Project for JPA

To build a working entity and repository example, create a Spring Boot project with the required dependencies.

Recommended Dependencies

  • Spring Data JPA
  • A JDBC driver for the selected database, such as MySQL Connector/J
  • Spring Web, if exposing REST endpoints
  • Validation, if validating request fields

For Maven projects, a typical dependency section for MySQL and JPA is:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <scope>runtime</scope>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

Use a Spring Boot parent or dependency-management setup so compatible dependency versions are managed consistently.

13. Configuring Database Connectivity

For a MySQL database named training_db, configure the connection in src/main/resources/application.properties.

spring.datasource.url=jdbc:mysql://localhost:3306/training_db
spring.datasource.username=${DB_USERNAME}
spring.datasource.password=${DB_PASSWORD}

spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

Set DB_USERNAME and DB_PASSWORD in the runtime environment. Do not store real production credentials in the source code.

The ddl-auto=update option can be useful in development, but production systems should generally use controlled database migrations and an appropriate validation setting.

14. Complete Example: Student Entity and Repository

The following example combines an entity class and repository interface for a student management application.

14.1 Student.java

package com.example.demo.entity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

@Entity
@Table(name = "students")
public class Student {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false, length = 100)
    private String name;

    @Column(nullable = false, unique = true, length = 150)
    private String email;

    @Column(nullable = false, length = 100)
    private String course;

    protected Student() {
    }

    public Student(String name, String email, String course) {
        this.name = name;
        this.email = email;
        this.course = course;
    }

    public Long getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getCourse() {
        return course;
    }

    public void setCourse(String course) {
        this.course = course;
    }
}

14.2 StudentRepository.java

package com.example.demo.repository;

import com.example.demo.entity.Student;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;
import java.util.Optional;

public interface StudentRepository
        extends JpaRepository<Student, Long> {

    Optional<Student> findByEmail(String email);

    List<Student> findByCourse(String course);

    List<Student> findByNameContainingIgnoreCase(String name);
}

Spring Data JPA derives query implementations from the method names. The repository can search by email, retrieve students by course, and find names containing a search term without requiring manual query implementations.

The unique email constraint should also be enforced in the database schema. In a real application, handle duplicate-email errors and validate input before attempting to save a student.

15. Understanding Derived Query Methods

Spring Data JPA can generate queries from repository method names. The method name describes the field or condition used to retrieve records.

Repository Method Purpose
findByName(String name) Finds records matching a name.
findByEmail(String email) Finds a record matching an email address.
findByCourse(String course) Finds records matching a course.
findByNameContaining(String name) Finds names containing the supplied text.
findByNameContainingIgnoreCase(String name) Performs a case-insensitive contains search, subject to database and provider behavior.
findByAgeGreaterThan(Integer age) Finds records with an age greater than the supplied value.
existsByEmail(String email) Checks whether a matching email exists.
countByCourse(String course) Counts records matching a course.
deleteByCourse(String course) Declares a delete operation for matching records; review its transaction and execution behavior.

Derived query methods are convenient for straightforward conditions. For complex joins, aggregates, or carefully optimized queries, an explicit JPQL or native SQL query may be more appropriate.

16. Creating Custom Queries with @Query

The @Query annotation allows a repository to declare a query explicitly. By default, a JPA query written in @Query is JPQL, which operates on entity names and mapped fields rather than directly on database table and column names.

16.1 JPQL Example

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;

public interface StudentRepository
        extends JpaRepository<Student, Long> {

    @Query("SELECT s FROM Student s WHERE s.course = :course")
    List<Student> findStudentsInCourse(
            @Param("course") String course
    );
}

The query refers to the entity Student and its field course. The @Param annotation binds the supplied method argument to the named query parameter.

16.2 Native SQL Example

@Query(
    value = "SELECT * FROM students WHERE course = :course",
    nativeQuery = true
)
List<Student> findStudentsUsingSql(
    @Param("course") String course
);

Native SQL uses database table and column names directly. It can be useful for database-specific queries, but it is less portable than JPQL. Parameter binding should be used rather than concatenating user input into query strings.

17. Pagination and Sorting in Repositories

Pagination retrieves a subset of records instead of loading an entire table. Sorting controls the order in which records are returned. Both are important for APIs that expose large datasets.

Pagination Example

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;

public interface StudentRepository
        extends JpaRepository<Student, Long> {

    Page<Student> findByCourse(
            String course,
            Pageable pageable
    );
}

A service or controller can create a Pageable request using Spring Data's paging utilities and pass it to the repository. The returned Page includes the current page of results and metadata such as total elements and total pages, depending on the query.

Sorting Example

import org.springframework.data.domain.Sort;

Sort sortByName = Sort.by("name").ascending();
List<Student> students = studentRepository.findAll(sortByName);

When accepting sort fields from an API request, allow only approved entity properties. Do not pass arbitrary user-provided values into dynamic query construction without validation.

18. Entity Relationships

JPA entities can be connected through relationships that represent associations between database tables.

Relationship Meaning Example
@OneToOne One entity is associated with one other entity. User and UserProfile.
@OneToMany One entity is associated with multiple entities. Department and Employees.
@ManyToOne Multiple entities can refer to one entity. Many Employees belong to one Department.
@ManyToMany Multiple entities can be associated with multiple entities. Students and Courses.

Example: Many-to-One Relationship

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;

@Entity
public class Employee {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @ManyToOne
    private Department department;

    protected Employee() {
    }
}

This mapping represents many employees associated with one department. In a real application, define the owning side and join-column mapping intentionally, and consider fetch behavior, cascading, and serialization when exposing relationships through APIs.

19. Entity Lifecycle and Persistence Context

JPA manages entity objects through a persistence context. An entity can move through several lifecycle states as it is created, persisted, retrieved, detached, or removed.

  • New or transient: The object has been created in Java but is not yet managed by the persistence context.
  • Managed: The persistence context tracks the entity, and changes may be synchronized to the database.
  • Detached: The object is no longer managed by the persistence context.
  • Removed: The entity is marked for deletion from the database.

Repository methods such as save() and findById() interact with JPA persistence behavior through Spring Data JPA. Within a transaction, managed entity changes may be detected and synchronized automatically at flush or commit time.

20. Transactions and Repository Operations

Transactions help ensure that related database operations are executed as a logical unit. Spring Data repository methods have transaction behavior, but service-level transactions are often useful when several operations must succeed or fail together.

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class StudentService {

    private final StudentRepository repository;

    public StudentService(StudentRepository repository) {
        this.repository = repository;
    }

    @Transactional
    public Student registerStudent(Student student) {
        return repository.save(student);
    }

    @Transactional(readOnly = true)
    public long getStudentCount() {
        return repository.count();
    }
}

The transaction annotation helps define the boundary of the operation. Review rollback rules and avoid performing slow external network operations inside database transactions unless the workflow specifically requires it.

21. Common Errors and Troubleshooting

Error or Symptom Possible Cause Solution
Not a managed type The entity is not discovered or is missing @Entity. Check entity annotations and package scanning.
No qualifying bean of type repository The repository is outside the scan path or configuration is incomplete. Check package structure and repository scanning configuration.
Entity has no identifier The entity has no valid primary-key mapping. Add a suitable @Id or supported composite-key mapping.
Table does not exist The schema is missing or mapped table name is incorrect. Check the database schema and apply migrations.
Unknown column Entity field mapping does not match the database schema. Review @Column mappings and migration scripts.
Duplicate key or unique constraint violation An inserted value conflicts with an existing unique value. Validate data and handle the database constraint exception.
LazyInitializationException A lazy relationship is accessed after the persistence context is no longer available. Load required data within a suitable transaction or use a deliberate fetch/query strategy.
Incorrect query validation JPQL refers to incorrect entity or property names. Check the entity name, mapped field names, parameter names, and query syntax.

22. Best Practices for Entities and Repositories

  • Use meaningful entity and repository names.
  • Define a valid primary key for every entity.
  • Keep the entity's no-argument constructor public or protected.
  • Use explicit table and column mappings when clarity or schema compatibility requires them.
  • Keep business logic in service or domain layers rather than controllers.
  • Use constructor injection for service dependencies.
  • Prefer derived query methods for simple conditions and custom queries for more complex requirements.
  • Use pagination and sorting for large datasets.
  • Define transaction boundaries according to business operations.
  • Use DTOs for API requests and responses when appropriate, instead of exposing entity objects directly.
  • Handle validation errors, missing records, and database constraint violations consistently.
  • Use migrations to manage production schema changes.
  • Be deliberate about cascading and lazy/eager loading for relationships.
  • Avoid Lombok-generated equality methods that include every relationship or mutable field without understanding the consequences.
  • Test repository queries and entity mappings against a suitable database.

23. Practical Exercise: Student Repository

Create a Spring Boot application that manages student records using JPA entities and repository interfaces.

Requirements

  1. Create a database named training_db.
  2. Configure the database connection in application.properties.
  3. Create a Student entity with ID, name, email, and course fields.
  4. Use @Entity, @Table, @Id, @GeneratedValue, and @Column where appropriate.
  5. Create a StudentRepository extending JpaRepository<Student, Long>.
  6. Add query methods for searching by email, course, and name.
  7. Implement a service that uses the repository.
  8. Create REST endpoints to add and retrieve students.
  9. Test repository methods and API responses.
  10. Handle duplicate emails and invalid student data.

Expected Outcome

After completing the exercise, learners should be able to map Java objects to database tables, define repository interfaces, perform CRUD operations, create query methods, and organize persistence logic within a Spring Boot application.

24. Interview Questions and Answers

Q1. What is a JPA entity?

A JPA entity is a Java class mapped to persistent data in a relational database. It is typically marked with the @Entity annotation.

Q2. What is the purpose of @Id?

@Id identifies the primary key of an entity, which allows the persistence provider to identify each persistent record.

Q3. What is the difference between @Entity and @Table?

@Entity marks a class as a persistent entity. @Table optionally specifies the database table name and related table metadata.

Q4. Why is a no-argument constructor required?

JPA entity classes must provide a public or protected no-argument constructor so the persistence provider can instantiate them.

Q5. What is Spring Data JPA?

Spring Data JPA simplifies repository implementation and provides common persistence operations and query-generation features.

Q6. What is JpaRepository?

JpaRepository is a Spring Data interface that provides common CRUD, paging, sorting, and JPA-specific repository functionality.

Q7. What do the generic types in JpaRepository mean?

In JpaRepository<Student, Long>, Student is the entity type and Long is the primary-key type.

Q8. What are derived query methods?

They are repository methods whose names describe query conditions, allowing Spring Data JPA to generate their implementations.

Q9. What is the purpose of @Query?

@Query declares a custom repository query, typically using JPQL, or native SQL when explicitly configured.

Q10. What is the difference between JPQL and native SQL?

JPQL queries entity names and mapped properties, while native SQL queries database tables and columns directly.

Q11. What is the purpose of @GeneratedValue?

It configures how entity identifiers are generated, using a supported strategy such as identity, sequence, table, or automatic selection.

Q12. Why should pagination be used?

Pagination returns a manageable subset of records, reducing unnecessary data transfer and memory usage for large result sets.

Q13. What is a persistence context?

A persistence context tracks managed entity instances and coordinates their state with the database during persistence operations.

Q14. What is @Transactional?

@Transactional declares transaction behavior for a method or class managed by Spring's transaction infrastructure.

Q15. How can the “Not a managed type” error be fixed?

Verify that the class has the correct @Entity annotation, that the correct persistence namespace is used, and that entity scanning includes its package.

25. Quick Revision Checklist

  • Understand the purpose of JPA entities and repository interfaces.
  • Know the role of @Entity, @Table, @Id, and @Column.
  • Understand primary-key generation strategies.
  • Create repository interfaces using JpaRepository.
  • Use built-in CRUD methods and derived query methods.
  • Write custom JPQL queries with @Query.
  • Understand pagination, sorting, and entity relationships.
  • Know how transactions and the persistence context work.
  • Troubleshoot entity scanning, mapping, and query errors.
  • Follow secure, maintainable persistence practices.

26. Conclusion

JPA entities and repository interfaces are fundamental components of database-driven Spring Boot applications. Entities map Java objects to relational tables, while repository interfaces provide a convenient abstraction for retrieving and modifying persistent data.

By learning entity annotations, primary-key generation, column mapping, repository methods, derived queries, custom JPQL, pagination, and transaction management, developers can build maintainable applications with less repetitive database-access code.

To learn more about Java persistence and backend development, explore the Advanced Java Training course at JustAcademy, visit the course demo registration page, or browse the JustAcademy website.

Previous Next
whatsapp