Skip to content

JPA Guide

ID Generation

  • GenerationType.AUTO : It dependecy on data base mostly it used SEQUNCE
  • GenerationType.Identity : It relies on auto-incremented database column
  • GenerationType.SEQUNCE : It uses databse sequnce to generate
  • GenerationType.TABLE : for pessimistic locks

@CreationTimestamp and @UpdateTimestamp

Query

image

Query Generation by Spring Data JPA

@Query

  • We can write JPQL query #### @Query JPQL using index parameters
  //JPQL Query using index params
    @Query("select p from Product p where p.name  =?1 or p.description=?2")
    public Product findByNameorDescriptionJPQLIndexParam(String name, String description);

#### @Query JPQL using named parameters

    //JPQL Query using named params
    @Query("select p from Product p where p.name  =:name or p.description=:desc")
    public Product findByNameorDescriptionJPQLNamedParam(@Param("name") String name, @Param("desc") String description);

@Query for Native SQL Queries using index parameters

    //Native SQl Query using index params
    @Query(value = "select * from products p where p.name  =?1 or p.description=?2" , nativeQuery = true)
    public Product findByNameorDescriptionSQLIndexParam(String name, String description);

@Query for Native SQL Queries using named parameters

    //Native SQL Query using named params

    @Query(value = "select * from products p where p.name  =:name or p.description=:desc" , nativeQuery = true)
    public Product findByNameorDescriptionSQLNamedParam(@Param("name") String name, @Param("desc") String description);

Named Queries

@NamedQuery for JPQL named Query

//Entity
@NamedQueries(
        {
                @NamedQuery(
                        name = "Product.findAllProductsOrderByNameDesc",
                        query = "select p from Product p order by p.name desc"
                ),
                @NamedQuery(
                        name = "Product.findByPrice",
                        query = "select p from Product p where p.price =:price"
                )
        }
)

// reposiroty 
public List<Product> findAllProductsOrderByNameDesc();
 public Product findByPrice(@Param("price") BigDecimal price);

@NamedNativeQuery for SQL Native named Query

@NamedNativeQueries(
        {
                @NamedNativeQuery(
                        name = "Product.findAllProductsOrderByNameAsc",
                        query = "select * from products p order by p.name asc",
                        resultClass = Product.class
                ),
                @NamedNativeQuery(
                        name = "Product.findBySku",
                        query = "select * from products p where p.stock_keeping_unit = ?1",
                        resultClass = Product.class
                )
        }
)
//repository
    @Query(nativeQuery = true)
    public Product findBySku (String sku);

    @Query(nativeQuery = true)
    public List<Product> findAllProductsOrderByNameAsc();

Mapping

image

One-to-One Mapping

Unidirectional mapping

  • Source entity has a relationship field that refers to the target entity and the source entity's table contains the foreign key image
public class Order {
    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "billing_address_id" , referencedColumnName = "id")
    private Address billingAddress;
    }

Bidirectional Mapping

  • Each entity has a relationship field that refers to each other and the target entity table contain the foreign key. The source entity must use the mappedBy attributr to define the bidirectional one-to-one mapping
public class Order {
    @OneToOne(cascade = CascadeType.ALL, mappedBy = "order", fetch = FetchType.LAZY)
    private Address billingAddress;
    }

    public class Address {
    @OneToOne(cascade = CascadeType.ALL )
    @JoinColumn(name = "billing_address_id", referencedColumnName = "id")
    private Order order;
  }  

One-to-Many Mapping

  • Child tables record reference the primary key or the parent table #### Unidirectional mapping : image

  • Parent entity will have OnetoMany relationship , Foreign key column in child table which referes to primary key of the parent table

   public class Order {
    //Default fetch type for one to many is LAZY
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinColumnn(name = "order_id" , referenceColumnName = "id")
    private Set<OrderItem> orderItemSets = new HashSet<>();

Bidirectional mapping :

image - Parent entity will have OnetoMany and child entity will have ManyToOne relationship , Foreign key column in child table which referes to primary key of the parent table

public class Order {
    //Default fetch type for one to many is LAZY
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "order")
    private Set<OrderItem> orderItemSets = new HashSet<>();
}

public class OrderItem {
    //Default fetch type of ManyToOne : EAGER
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "order_id", referencedColumnName = "id")
    private Order order;

Many-to-Many Mapping

image - It use a table to store association that join two entities.

#### Unidirectional mapping : image - Source entity has @ManyToMany annotation

public class User {
 @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinTable(
            name = "users_roles",
            joinColumns = @JoinColumn(
                    name = "user_id", referencedColumnName = "id"
            ),
            inverseJoinColumns = @JoinColumn(
                    name = "role_id", referencedColumnName = "id"
            )
    )
    private Set<Role> roles = new HashSet<>();
    }

Bidirectional mapping :

  • Both entities have @ManyToMany annotation image
public class User {
 @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinTable(
            name = "users_roles",
            joinColumns = @JoinColumn(
                    name = "user_id", referencedColumnName = "id"
            ),
            inverseJoinColumns = @JoinColumn(
                    name = "role_id", referencedColumnName = "id"
            )
    )
    private Set<Role> roles = new HashSet<>();
    }

    public class Role {

    @ManyToMany(mappedBy = "roles" , cascade = {CascadeType.PERSIST, CascadeType.MERGE} , fetch = FetchType.EAGER)
    private Set<User> users = new HashSet<>();

}

JPA Inheritance

Mapped Super Class

 @MappedSuperclass
public abstract class BaseEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
}
//---
 @Entity
public class OrderHeader extends BaseEntity {

    private String customerName;

    public String getCustomerName() {
        return customerName;
    }

    public void setCustomerName(String customerName) {
        this.customerName = customerName;
    }
}

Single Table

image image image image

  • It will create single table for all subclasses it will include all fields from parent and all child classes and it will have a discriminator column for identification of rows for child
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "vehicle_type")
public abstract class Vehicle {

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

    public Long getId() {
        return id;
    }

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

@Entity
@DiscriminatorValue("car")
public class Car extends Vehicle{

    private String trimLevel;

    public String getTrimLevel() {
        return trimLevel;
    }

    public void setTrimLevel(String trimLevel) {
        this.trimLevel = trimLevel;
    }
}
@Entity
@DiscriminatorValue("truck")
public class Truck extends Vehicle{

    private Integer payload;

    public Integer getPayload() {
        return payload;
    }

    public void setPayload(Integer payload) {
        this.payload = payload;
    }
}

Joined Table

image image image

  • Each entity has its own table with shared attribute from parent will have foreign key to parent tables
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Instrument {

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

}
@Entity
public class Piano extends Instrument {

    private Integer numberOfKeys;

    public Integer getNumberOfKeys() {
        return numberOfKeys;
    }

    public void setNumberOfKeys(Integer numberOfKeys) {
        this.numberOfKeys = numberOfKeys;
    }
}
@Entity
public class ElectricGuitar extends Guitar{

    private Integer numberOfPickups;

    public Integer getNumberOfPickups() {
        return numberOfPickups;
    }

    public void setNumberOfPickups(Integer numberOfPickups) {
        this.numberOfPickups = numberOfPickups;
    }
}
@Entity
public class Guitar extends Instrument {

    private Integer numberOfStrings;

    public Integer getNumberOfStrings() {
        return numberOfStrings;
    }

    public void setNumberOfStrings(Integer numberOfStrings) {
        this.numberOfStrings = numberOfStrings;
    }
}

Tables per class

image image image

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Mammal {

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

    private Integer bodyTemp;

    private String species;

    public Long getId() {
        return id;
    }

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

    public Integer getBodyTemp() {
        return bodyTemp;
    }

    public void setBodyTemp(Integer bodyTemp) {
        this.bodyTemp = bodyTemp;
    }

    public String getSpecies() {
        return species;
    }s

    public void setSpecies(String species) {
        this.species = species;
    }
}
@Entity
public class Dog extends Mammal {

    private String breed;

    public String getBreed() {
        return breed;
    }

    public void setBreed(String breed) {
        this.breed = breed;
    }
}

@Entity
public class Dolphin extends Mammal {

    private Boolean hasSpots;

    public Boolean getHasSpots() {
        return hasSpots;
    }

    public void setHasSpots(Boolean hasSpots) {
        this.hasSpots = hasSpots;
    }
}
  • Each entity has its own table and There is no explicit foreign key relationship between the tables representing subclasses and the superclass.