How to use Criteria Queries in Spring Boot Data Jpa Application

前端 未结 6 502
死守一世寂寞
死守一世寂寞 2020-12-04 23:10

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

public interface StudentRepository extends CrudRepos         


        
相关标签:
6条回答
  • 2020-12-04 23:34

    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<Customer> {
    
      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);
          }
        };
    }
    

    The above can be simplified using lambdas as follows

    public interface CustomerRepository extends 
      CrudRepository<Customer, Long>, 
      JpaSpecificationExecutor<Customer> {
    
      default List<Customer> findCustomers() {
        return findAll(
          (root, query, cb) -> {
             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

    0 讨论(0)
  • 2020-12-04 23:34

    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

    0 讨论(0)
  • 2020-12-04 23:36

    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.

    0 讨论(0)
  • 2020-12-04 23:48

    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

    0 讨论(0)
  • 2020-12-04 23:53

    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

    0 讨论(0)
  • 2020-12-04 23:54

    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

    0 讨论(0)
提交回复
热议问题