Spring Boot HandBook

    Understanding Entity Mapping in JPA with Examples: @Entity, @Id, @Column, @Table, and Relationships#

    Entity mapping is at the core of the Java Persistence API (JPA) and allows developers to map Java objects (entities) to database tables. By using various annotations, we can define how each field in a class corresponds to columns in a table and how relationships between entities are handled.

    This article will cover the most common JPA annotations like @Entity, @Id, @Column, @Table, and relationships like @OneToOne, @OneToMany, @ManyToOne, and @ManyToMany.

    1. What is Entity Mapping?#

    Entity mapping is the process of mapping a Java object (an entity) to a corresponding database table using annotations. Each field in the entity class is mapped to a column in the database, and relationships between entities are mapped to reflect foreign keys, join tables, etc.

    JPA provides a set of annotations that simplify this mapping process, eliminating the need to write SQL queries manually.

    2. Common JPA Annotations Explained#

    @Entity#

    The @Entity annotation is used to mark a class as a JPA entity. This tells JPA that this class should be persisted in the database.

    @Entity public class Book { // Fields and methods }

    Once the class is annotated with @Entity, JPA automatically maps it to a table in the database. If no table name is specified, the class name will be used by default.

    @Id#

    The @Id annotation marks a field as the primary key for the entity. Every entity must have an @Id field.

    @Entity public class Book { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String title; private String author; }

    In this case, the id field is the primary key, and the @GeneratedValue annotation specifies that it will be auto-generated.

    @Column#

    The @Column annotation is used to specify the mapping between a field and a database column. It allows customization of column properties such as name, length, nullability, etc.

    @Entity public class Book { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "book_title", length = 100, nullable = false) private String title; @Column(nullable = false) private String author; }

    Here, the title field is mapped to a column named book_title in the database, and the length and nullable properties are customized.

    @Table#

    The @Table annotation is used to specify the table name for the entity. If the table name differs from the entity class name, you can use this annotation.

    java Copy code @Entity @Table(name = "library_books") public class Book { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false) private String title; @Column(nullable = false) private String author; }

    In this example, the Book entity is mapped to the library_books table instead of the default table name, which would have been Book.

    3. Defining Relationships Between Entities#

    @OneToOne#

    A @OneToOne relationship maps one entity to another entity. This is used when an entity has a single related entity.

    @Entity public class Author { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; @OneToOne private Address address; }

    Here, each Author has a single Address, and each Address is linked to one Author.

    @OneToMany#

    A @OneToMany relationship indicates that one entity can be associated with multiple related entities. For example, one Author can write many Books.

    @Entity public class Author { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; @OneToMany(mappedBy = "author") private List<Book> books; }

    In this case, an Author can have multiple Book objects. The mappedBy attribute tells JPA that the author field in the Book entity manages the relationship.

    @ManyToOne#

    A @ManyToOne relationship is the inverse of @OneToMany. In this case, many Books can belong to a single Author.

    @Entity public class Book { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @ManyToOne private Author author; }

    This defines that many Book entities can refer to a single Author.

    @ManyToMany#

    A @ManyToMany relationship represents a relationship where multiple entities can be associated with multiple other entities. For example, multiple Books can have multiple Categories.

    @Entity public class Book { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @ManyToMany @JoinTable( name = "book_category", joinColumns = @JoinColumn(name = "book_id"), inverseJoinColumns = @JoinColumn(name = "category_id")) private Set<Category> categories; }

    This creates a many-to-many relationship between Book and Category, with a join table named book_category.

    4. Example Code for Entity Mapping and Relationships#

    Let’s take a practical example with three entities: Author, Book, and Category.

    @Entity public class Author { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false) private String name; @OneToMany(mappedBy = "author", cascade = CascadeType.ALL) private List<Book> books; } @Entity public class Book { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false) private String title; @ManyToOne @JoinColumn(name = "author_id") private Author author; @ManyToMany @JoinTable( name = "book_category", joinColumns = @JoinColumn(name = "book_id"), inverseJoinColumns = @JoinColumn(name = "category_id")) private Set<Category> categories; } @Entity public class Category { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false) private String name; @ManyToMany(mappedBy = "categories") private Set<Book> books; }
    • The Author entity is linked to the Book entity with a @OneToMany relationship.
    • The Book entity has a @ManyToOne relationship with Author and a @ManyToMany relationship with Category.
    • The Category entity has a @ManyToMany relationship with Book.

    This setup allows each author to write multiple books, each book to belong to multiple categories, and each category to have multiple books.

    For beginners, it's essential to explain what cascade = CascadeType.ALL means, as it can be confusing without proper context.#

    What is cascade = CascadeType.ALL?#

    In JPA, cascading allows you to propagate certain operations (like saving, deleting, or updating) from a parent entity to its related entities automatically. This can be very useful when dealing with relationships, as it reduces the need to explicitly manage each related entity.

    • CascadeType.ALL means that all operations (persist, merge, remove, refresh, and detach) should be cascaded from the parent entity to its related entities.

    Example:#

    @Entity public class Author { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false) private String name; @OneToMany(mappedBy = "author", cascade = CascadeType.ALL) private List<Book> books; }

    In this example:

    • The Author entity has a list of Book entities.
    • The cascade = CascadeType.ALL tells JPA to automatically apply certain operations (like saving or deleting) to the Book entities when performed on the Author.

    Why use Cascade?#

    Imagine you want to save an Author along with a list of their Books. Without cascade, you would need to:

    1. Save the Author.
    2. Explicitly save each Book object in the list.

    With cascade = CascadeType.ALL, saving the Author will automatically save all the Books associated with that author.

    Cascade Types Explained:#

    Here are the different types of cascade options in JPA:

    • PERSIST: When the parent is persisted (saved), the related entities are also persisted.
    • MERGE: When the parent is updated, the related entities are updated.
    • REMOVE: When the parent is deleted, the related entities are deleted.
    • REFRESH: If the parent is refreshed from the database, the related entities are refreshed.
    • DETACH: When the parent is detached from the persistence context, the related entities are also detached.
    • ALL: All of the above cascade operations are applied.

    By specifying CascadeType.ALL, you're applying all these cascade operations to the related entities, so operations like saving, updating, and deleting are automatically handled for you.

    For beginners, it's essential to understand that cascading can help manage relationships more easily, but it also comes with risks. For example, if you delete a parent entity with CascadeType.REMOVE, it will delete all related entities, which may not always be desirable. That's why it's important to use it carefully based on your application's needs.

    Updated Example Code:#

    Here’s an updated example with an explanation of cascade = CascadeType.ALL:

    @Entity public class Author { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false) private String name; // The CascadeType.ALL propagates all operations like save, delete, and update from Author to Books @OneToMany(mappedBy = "author", cascade = CascadeType.ALL) private List<Book> books; }

    In this article, we explored the essentials of entity mapping in JPA, including key annotations like @Entity, @Id, @Column, @Table, and the different types of relationships such as @OneToOne, @OneToMany, @ManyToOne, and @ManyToMany. Understanding these concepts is crucial for effectively working with JPA and managing the persistence of Java objects in a relational database.

    Last updated on Oct 25, 2024