JpaRepository in Spring Data JPA

JpaRepository in Spring Data JPA | JpaRepository internally extends PaginingAndSortingRpository and CrudRepository. Therefore, CRUD operations and PageAndSort are also available in JpaRepository. It also has JPA concepts like Date and Time, Lobs(BLOB, CLOB), Collection Mapping, ASSOCIATION MAPPING, JOINS, COMPONENT MAPPING, etc.

In JpaRepository we can define custom queries using one of the following approaches:-

  1. findBy
  2. @Query
  • Through JpaReposity we can perform association mapping (one to one/ one to many/ many to one /many to many) with Joins for data fetch.
  • We can also perform standard projections (selecting only specific columns) for data fetch using custom queries.
  • We can also perform function/procedure calls using Data JPA.

In CrudRepository and PagingAndSortingRepository findAll() methods are used to return Iterable but the JpaRepository interface extends ListCrudRepository and ListPagingAndSortingRepository which return List.

public interface JpaRepository<T, ID> extends ListCrudRepository<T, ID>, 
  ListPagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
}

Working with Date and Time in Spring Data JPA

Annotation @Temporal needs input from one Enum TemporalType which has 3 possible values:-

  • DATE
  • TIME
  • TIMESTAMP

If we did not specify any format in the code, the default storage is TIMESTAMP.

We can use the variable of type java.util.Date class that internally maps with different types based on enum selection:-

  • DATE — ex: 10/01/2021
  • TIME — 9:00:00
  • TIMESTAMP — ex: 10/01/2021 9:00:00

Entity class:-

@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Product {
   @Id
   private Integer pid;
   private String pcode;
   private Double pcost;

   @Temporal(TemporalType.DATE)
   private Date dteA;

   @Temporal(TemporalType.TIME)
   private Date dteB;

   @Temporal(TemporalType.TIMESTAMP)
   private Date dteC;
}

Repository:-

public interface ProductRepository extends JpaRepository<Product, Integer> { }

In application.properties file:-

spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.format_sql=true

Runner class to insert data:-

@Component
public class ProductRunner implements CommandLineRunner {

   @Autowired
   private ProductRepository productRepository;

   @Override
   public void run(String... args) throws Exception {
      productRepository.save(new Product(100, "ABC", 500.0, new Date(), 
                new Date(), new Date()));
      productRepository.findAll().forEach(System.out::println);
   }

}

Formatting java.util.Date

See more Date and Time Patterns here.

import java.text.SimpleDateFormat;
import java.util.Date;
public class Test {
   public static void main(String[] args) {
      Date dte = new Date();
      SimpleDateFormat sdf= new SimpleDateFormat("MMM dd,YYYY hh:mm:ss SSS");
      String pattern = sdf.format(dte);
      System.out.println(pattern);
   }
}

LOB (Large Objects) – @Lob in Spring Data JPA

@Lob annotation is given in Spring Data JPA to work with BLOB and CLOB.

  • BLOBbyte[] + @Lob:- Images, Audio, Videos, PDFs, Docs, etc
  • CLOBchar[] + @Lob:- Large Text Data
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Product {
   @Id
   private Integer pid;
   private String pcode;
   private Double pcost;

   @Lob
   @Column(columnDefinition = "LONGBLOB")
   private byte[] img;

   @Lob
   private char[] data;
}

If we don’t specify @Column(columnDefinition = “LONGBLOB”), MySQL will take tinyblob.

  • TINYBLOB: Can store up to 255 bytes.
  • BLOB (or TEXT): Can store up to 65,535 bytes (64 KB).
  • MEDIUMBLOB: Can store up to 16,777,215 bytes (16 MB).
  • LONGBLOB: Can store up to 4,294,967,295 bytes (4 GB).
@Component
public class ProductRunner implements CommandLineRunner {

   @Autowired
   private ProductRepository productRepository;

   @Override
   public void run(String... args) throws Exception {
      FileInputStream fis = new FileInputStream("C:/Users/Know/Downloads/img.webp");
      byte[] img = new byte[fis.available()];
      fis.read(img);

      String dataStr = "Lorem Ipsum is simply dummy text of the printing"+
                                " and typesetting industry.";
      char[] data = dataStr.toCharArray();
      fis.close();

      productRepository.save(new Product(100, "ABC", 500.0, img, data));
   }

}

Collections Mapping in Spring Data JPA

Data JPA supports storing collection data in database tables. In the model class, all primitives are stored in one table (parent table), for every collection variable one child table is created.

Supported Types: List, Set, and Map.

  • studentId — Integer
  • studentMarks— List
  • studentSubjst– Set
  • studentLabs — Map

Every Collection Variable in the Model class is mapped with one Database table(Child table).

Types of Collection (in Data Type):-

  • Index-based collections (List, Map)
  • Non-Index-based collections (Set)
  • When we add data, the list gets an index number starting from zero by default.
  • The map key behaves like an index (it is unique).
  • The Set never contains such a format.

List and Map are index-based collections. So, for these variables, a child table is created using 3 columns: Key Column (Join Key Col/ foreign key Column), Element(Data) Column, and Index (position) column. At the same time, Set comes under non-index based. So, only 2 columns are provided for the child table -> Key Column, Element Column.

For every collection variable, we must apply: @ElementCollection
Optional Annotation: @CollectionTable, @Column, @OrderColumn, @MapKeyColumn.

@ElementCollection says one collection variable –> one child table.

package com.knowprogram.demo;

import java.util.List;
import java.util.Map;
import java.util.Set;

import jakarta.persistence.Column;
import jakarta.persistence.ElementCollection;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Data;

@Entity
@Data
@Table
@NoArgsConstructor
@AllArgsConstructor
public class Student {
   @Id
   @Column(name = "sid")
   private Integer stdId;

   @Column(name = "sname")
   private String stdName;

   @Column(name = "sfee")
   private Double stdFee;

   @ElementCollection
   private Set<String> subjects;

   @ElementCollection
   private List<Integer> marks;

   @ElementCollection
   private Map<String, String> labExam;
}
package com.knowprogram.demo;

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

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

After running the application, 4 tables get created as follows:-

Hibernate: 
    create table student (
        sid integer not null,
        sfee float(53),
        sname varchar(255),
        primary key (sid)
    ) engine=InnoDB
Hibernate: 
    create table student_lab_exam (
        student_sid integer not null,
        lab_exam varchar(255),
        lab_exam_key varchar(255) not null,
        primary key (student_sid, lab_exam_key)
    ) engine=InnoDB
Hibernate: 
    create table student_marks (
        student_sid integer not null,
        marks integer
    ) engine=InnoDB
Hibernate: 
    create table student_subjects (
        student_sid integer not null,
        subjects varchar(255)
    ) engine=InnoDB
Hibernate: 
    alter table student_lab_exam 
       add constraint FKnd651khr8av5me3l4wd3le5gy 
       foreign key (student_sid) 
       references student (sid)
Hibernate: 
    alter table student_marks 
       add constraint FKle2pr6bv9wdq2jsodbasd8ohx 
       foreign key (student_sid) 
       references student (sid)
Hibernate: 
    alter table student_subjects 
       add constraint FKpua58lpobui850uek8l76lubl 
       foreign key (student_sid) 
       references student (sid)

We can also specify the column names, table names, element columns, and index columns as follows:-

@Entity
@Data
@Table
@NoArgsConstructor
@AllArgsConstructor
public class Student {
   @Id
   @Column(name = "sid")
   private Integer stdId;

   @Column(name = "sname")
   private String stdName;

   @Column(name = "sfee")
   private Double stdFee;

   @ElementCollection
   @CollectionTable(name = "std_sub_tab", // table name
         joinColumns = @JoinColumn(name = "sid") // key column
   )
   @Column(name = "subj") // element column
   private Set<String> subjects;

   @ElementCollection
   @CollectionTable(name = "std_marks_tab", // table name
         joinColumns = @JoinColumn(name = "sid"))
   @Column(name = "mrks") // element column
   private List<Integer> marks;

   @ElementCollection
   @CollectionTable(name = "std_lab_exam", // table name
         joinColumns = @JoinColumn(name = "sid"))
   @Column(name = "grade") // element column
   @MapKeyColumn(name = "lname") // index column
   private Map<String, String> labExam;
}

Table creation queries:-

Hibernate: 
    create table std_lab_exam (
        sid integer not null,
        grade varchar(255),
        lname varchar(255) not null,
        primary key (sid, lname)
    ) engine=InnoDB
Hibernate: 
    create table std_marks_tab (
        sid integer not null,
        mrks integer
    ) engine=InnoDB
Hibernate: 
    create table std_sub_tab (
        sid integer not null,
        subj varchar(255)
    ) engine=InnoDB
Hibernate: 
    create table student (
        sid integer not null,
        sfee float(53),
        sname varchar(255),
        primary key (sid)
    ) engine=InnoDB
Hibernate: 
    alter table std_lab_exam 
       add constraint FKr3ygpw67uglaua6pi7kj9gjtn 
       foreign key (sid) 
       references student (sid)
Hibernate: 
    alter table std_marks_tab 
       add constraint FKoevmevl8hw6e1bjhh8gwcb023 
       foreign key (sid) 
       references student (sid)
Hibernate: 
    alter table std_sub_tab 
       add constraint FKsqb9g6gbt1m541xjpdlmxfptr 
       foreign key (sid) 
       references student (sid)

Let us insert some data:-

@Component
public class TestDataRunner implements CommandLineRunner {

   @Autowired
   private StudentRepository studentRepository;

   @Override
   public void run(String... args) throws Exception {
      studentRepository.save(
         new Student(10, "SAM", 300.0, 
            Set.of("ENG", "MAT", "SCI"), 
            List.of(90, 75, 80),
            Map.of("CD", "A+", "Java", "A", "CHEM", "B+")
         )
      );
   }
}

Tables and their data:-

mysql> show databases;
mysql> use test;
mysql> show tables;
mysql> select * from student;
+-----+------+-------+
| sid | sfee | sname |
+-----+------+-------+
|  10 |  300 | SAM   |
+-----+------+-------+
mysql> select * from std_sub_tab;
+-----+------+
| sid | subj |
+-----+------+
|  10 | MAT  |
|  10 | SCI  |
|  10 | ENG  |
+-----+------+
mysql> select * from std_marks_tab;
+-----+------+
| sid | mrks |
+-----+------+
|  10 |   90 |
|  10 |   75 |
|  10 |   80 |
+-----+------+
mysql> select * from std_lab_exam;
+-----+-------+-------+
| sid | grade | lname |
+-----+-------+-------+
|  10 | A+    | CD    |
|  10 | B+    | CHEM  |
|  10 | A     | Java  |
+-----+-------+-------+

If you enjoyed this post, share it with your friends. Do you want to share more information about the topic discussed above or do you find anything incorrect? Let us know in the comments. Thank you!

Leave a Comment

Your email address will not be published. Required fields are marked *