SpringBoot- SpringBoot JpaRepository

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:

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 **** has an option query-lookup-strategy which defaults to -**create-if-not-found" which will generate queries for us.**The default is -create-if-not-found-. Other options are -create" or -use-declared-query-.

<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]