How to use Criteria Queries in Spring Boot Data Jp

2019-01-18 06:21发布

I have an application that uses Spring Boot Data jpa . So far i am using a repository like this

public interface StudentRepository extends CrudRepository<StudentEntity, Integer>{
    @Query(value = "" 
        + "SELECT s.studentname "
        + "FROM   studententity s, "
        + "       courseentity c "
        + "WHERE  s.courseid = c.courseid "
        + "       AND s.courseid IN (SELECT c.courseid "
        + "                          FROM   courseentity c "
        + "                          WHERE  c.coursename = ?1)")
    List<String> nameByCourse(String coursename);
}

How can i make use of Criteria Query that Hibernate provides for such cases in a Spring Boot Application

6条回答
小情绪 Triste *
2楼-- · 2019-01-18 06:50

From the docs

To enrich a repository with custom functionality you first define an interface and an implementation for the custom functionality. Use the repository interface you provided to extend the custom interface.

Define an interface like so

public interface StudentRepositoryCustom {

    List<String> nameByCourse(String coursename);

}

Then define a custom implementation of this interface like so

@Service
class StudentRepositoryImpl implements StudentRepositoryCustom {

    @PersistenceContext
    private EntityManager em;

    public List<String> nameByCourse(String coursename) {            
        CriteriaBuilder cb = em.getCriteriaBuilder();
        //Using criteria builder you can build your criteria queries.
    }

}

Now you can extend this custom repository implementaion in your JPA repository like so.

public interface StudentRepository extends CrudRepository<StudentEntity, Integer>, StudentRepositoryCustom {

}

Learn more about criteria query and criteria builder here

查看更多
地球回转人心会变
3楼-- · 2019-01-18 06:50

JPA 2 introduces a criteria API that can be used to build queries programmatically.

You can extend a new interface from JpaSpecificationExecutor

public interface CustomerRepository extends CrudRepository<Customer, Long>, JpaSpecificationExecutor {
    default List<Customer> findCustomers() {
    return findAll(CustomerSpecs.findCustomers());
}

Then create a customer specs

public final class CustomerSpecs {

public static Specification<Customer> findCustomers() {
    return new Specification<Customer>() {
        public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query,
        CriteriaBuilder builder) {

     LocalDate date = new LocalDate().minusYears(2);
     return builder.lessThan(root.get("birthday"), date);
  }
};
}

For more details, refer this spring doc here

https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#specifications

查看更多
The star\"
4楼-- · 2019-01-18 06:50

you can refer to Query creation into spring data JPA documentation and take a look at the table, JPA give multiple Query creation from method names where you can avoid using a String query

查看更多
萌系小妹纸
5楼-- · 2019-01-18 06:53

It's very complicated to create specifications using JPA Criteria because the API is very verbose and instrusive.

With the Lambda JDK 8, you can create high very typed-queries using simples predicates.

@Test
public void testSimpleSpec() {
    String expected = 
        "select e0.id, e0.name "
        + "from Customer e0 "
        + "where (e0.regionCode = :p0)";

    Consumer<Query<Customer>> regionCode1 = 
        q -> q.where(i -> i.getRegionCode()).eq(1L);

    NativeSQLResult result = new QueryBuilder()
        .from(Customer.class)
        .whereSpec(regionCode1)
        .select(i -> i.getId())
        .select(i -> i.getName())
        .to(new NativeSQL())
        ;
    String actual = result.sql();

    Assert.assertEquals(expected, actual);
    Assert.assertEquals(result.params().get("p0"), 1L);
}

You can isolate the conditions and to reuse in others queries, ie, specifications.

https://github.com/naskarlab/fluent-query

https://github.com/naskarlab/fluent-query-eclipselink

查看更多
何必那么认真
6楼-- · 2019-01-18 06:57

With Spring-boot-jpa you are able to use entityManager nearly everywhere. The most commom way is to create an own interface for custom methods.

public interface StudentCustomRepository {

    void anyCustomMethod();
    Student getStudentByName(String name);
}

Then implement this interface to a service class where you are able to autowire and use the entityManager:

@Service
public class StudentCustomRepositoryServiceImpl implements StudentCustomRepository {

     @PersistenceContext
     private EntityManager em;

     @Override
     public void anyCustomMethod(){
         //here use the entityManager
     }

     @Override
     StudentEntity getStudentByName(String name){
         Criteria crit = em.unwrap(Session.class).createCriteria(StudentEntity.class);
         crit.add(Restrictions.eq("name", name));
         List<StudentEntity> students = crit.list();
         return students.get(0);
     }
 }

You can also decide to implement your StudentRepository to your new StudentCustomRepositoryServiceImpl class.

查看更多
Ridiculous、
7楼-- · 2019-01-18 07:00

According to Spring doc HibernateTemplate:

NOTE: Hibernate access code can also be coded in plain Hibernate style. Hence, for newly started projects, consider adopting the standard Hibernate style of coding data access objects instead, based on SessionFactory.getCurrentSession(). This HibernateTemplate primarily exists as a migration helper for Hibernate 3 based data access code, to benefit from bug fixes in Hibernate 4.x.

While according to Hibernate doc:

New development should focus on the JPA javax.persistence.criteria.CriteriaQuery API. Eventually, Hibernate-specific criteria features will be ported as extensions to the JPA javax.persistence.criteria.CriteriaQuery.

So its better to use JPQL Criteria:JPA Criteria API Queries

Example:

  CriteriaBuilder cb = entityManager.getCriteriaBuilder();

  CriteriaQuery<Country> q = cb.createQuery(Country.class);
  Root<Country> c = q.from(Country.class);
  q.select(c);

where entityManager should be @Autowired. For detail info, see above link

查看更多
登录 后发表回答