SpringBoot - JpaRepository
JpaRepository provides some JPA related method such as flushing the persistence context and delete record in a batch. JpaRepository extends PagingAndSortingRepository which in turn extends CrudRepository.
Their main functions are:
-
CrudRepository mainly provides CRUD functions.
-
PagingAndSortingRepository provide methods to do pagination and sorting records.
-
JpaRepository provides some JPA related method such as flushing the persistence context and delete record in a batch.
Because of the inheritance mentioned above, JpaRepository will have all the functions of CrudRepository and PagingAndSortingRepository.
Custom Queries
Spring Data JPA provides three different approaches for creating custom queries with query methods. Each of these approaches is described in following.
Using Method Name
-
Spring Data JPA has a built in query creation mechanism which can be used for parsing queries straight from the method name of a query method.
-
the method names of your repository interface are created by combining the property names of an entity object and the supported keywords.
public interface PersonRepository extends Repository<User, Long> { List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname); // Enables the distinct flag for the query List<Person> findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname); List<Person> findPeopleDistinctByLastnameOrFirstname(String lastname, String firstname); // Enabling ignoring case for an individual property List<Person> findByLastnameIgnoreCase(String lastname); // Enabling ignoring case for all suitable properties List<Person> findByLastnameAndFirstnameAllIgnoreCase(String lastname, String firstname); // Enabling static ORDER BY for a query List<Person> findByLastnameOrderByFirstnameAsc(String lastname); List<Person> findByLastnameOrderByFirstnameDesc(String lastname); }
JPA Named Queries
Spring Data JPA provides also support for the JPA Named Queries. You have got following alternatives for declaring the named queries:
-
You can use either named-query XML element or @NamedQuery annotation to create named queries with the JPA query language.
-
You can use either named-native-query XML element or @NamedNative query annotation to create queries with SQL if you are ready to tie your application with a specific database platform.
The only thing you have to do to use the created named queries is to name the query method of your repository interface to match with the name of your named query. See below Example code
@Entity
@NamedQuery(name = "Person.findByName", query = "SELECT p FROM Person p WHERE LOWER(p.lastName) = LOWER(?1)")
@Table(name = "persons")
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(name = "creation_time", nullable = false)
private Date creationTime;
@Column(name = "first_name", nullable = false)
private String firstName;
}
The relevant part of my PersonRepository interface looks following
public interface PersonRepository extends JpaRepository<Person, Long> {
//A list of persons whose last name is an exact match with the given last name.
public List<Person> findByName(String lastName);
}
@Query Annotation
-
The @Queryannotation can be used to create queries by using the JPA query language and to bind these queries directly to the methods of your repository interface.
-
When the query method is called, Spring Data JPA will execute the query specified by the @Query annotation
-
If there is a collision between the @Query annotation and the named queries, the query specified by using @Query annotation will be executed
public interface ProductRepository extends CrudRepository<Product, Long> { @Query("FROM Product") List<Product> findAllProducts(); }
You may use positional parameters instead of named parameters in queries. Positional parameters are prefixed with a question mark (?) followed the numeric position of the parameter in the query. The Query.setParameter(integer position, Object value) method is used to set the parameter values.
public List findWithName(String name) {
return em.createQuery(
-SELECT c FROM Customer c WHERE c.name LIKE ?1")
.setParameter(1, name)
.getResultList();
}
Automatic Query Generation
The **
<jpa:repositories base-package="com.gordondickens.myapp.repository"
query-lookup-strategy="create-if-not-found"/>
To create a find method that effectively does @Query(“FROM Product p where p.productId =:productId”)
public interface ProductRepository extends CrudRepository<Product, Long> {
...
@Query
Product findByProductId(String productId);
...
}
Example
//Student.java
package app.entity;
@Entity
@Table(name = "student")
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int sno;
@Column(name = "name")
private String name;
@Column(name = "address")
private String address;
@Override
public String toString() {
String str = "Student[" + "Sno: " + getSno() + ", Name:" + getName() + ", " + "Address : " + getAddress() + "]";
return str;
}
//Setters & getters
}
//StudentRepository.java
public interface StudentRepository extends CrudRepository<Student, Long> {
List<Student> findBySno(int sno);
List<Student> findByName(String name);
// custom query example and return a stream
@Query("select c from Student c where c.address = :address")
Stream<Student> findByAddress(@Param("address") String address);
}
//Application.java
package app;
@SpringBootApplication
public class Application implements CommandLineRunner {
@Autowired
DataSource dataSource;
@Autowired
StudentRepository repository;
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
@Transactional(readOnly = true)
@Override
public void run(String... args) throws Exception {
System.out.println("DATASOURCE = " + dataSource);
System.out.println("\n1.findAll()...");
for (Student student : repository.findAll()) {
System.out.println(student);
}
System.out.println("\n2.findByName(String name)...");
for (Student student : repository.findByName("Satya")) {
System.out.println(student);
}
System.out.println("\n3.findByAddress(@Param(\"name\"))...");
try (Stream<Student> s =repository.findByAddress("Vijayawada")) {
s.forEach(x -> System.out.println(x));
System.out.println("Done!");
exit(0);
}
}
}
1.findAll()...
Student[Sno: 0, Name:null, Address : null]
Student[Sno: 101, Name:Satya, Address : VIJAYAWADA]
Student[Sno: 102, Name:Satya, Address : Vijayawada]
Student[Sno: 147, Name:kumar, Address : Hyderabad]
Student[Sno: 189, Name:Satya, Address : Vijayawada]
Student[Sno: 508, Name:Satya, Address : Hyd]
2.findByName(String name)...
Student[Sno: 101, Name:Satya, Address : VIJAYAWADA]
Student[Sno: 102, Name:Satya, Address : Vijayawada]
Student[Sno: 189, Name:Satya, Address : Vijayawada]
Student[Sno: 508, Name:Satya, Address : Hyd]
4.findByAddress(@Param("name") String name)...
Student[Sno: 101, Name:Satya, Address : VIJAYAWADA]
Student[Sno: 102, Name:Satya, Address : Vijayawada]
Student[Sno: 189, Name:Satya, Address : Vijayawada]