如何在Spring Boot Data Jpa应用程序中使用Criteria Queries

时间:2017-05-31 07:13:52

标签: hibernate spring-boot spring-data-jpa

我有一个使用 Spring Boot Data jpa 的应用程序。 到目前为止,我正在使用像这样的存储库

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

如何利用Hibernate在Spring Boot应用程序中为此类情况提供的 Criteria Query

6 个答案:

答案 0 :(得分:18)

来自docs

  

要使用自定义功能丰富存储库,首先要为自定义功能定义接口和实现。使用您提供的存储库接口来扩展自定义接口。

定义一个这样的界面

public interface StudentRepositoryCustom {

    List<String> nameByCourse(String coursename);

}

然后定义此接口的自定义实现,如此

@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.
    }

}

现在,您可以在JPA存储库中扩展此自定义存储库实现。

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

}

详细了解条件查询和条件构建器here

答案 1 :(得分:4)

使用Spring-boot-jpa,您几乎可以在任何地方使用entityManager。最常见的方法是为自定义方法创建自己的interface

public interface StudentCustomRepository {

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

然后将此接口实现到服务类,您可以在其中自动装配并使用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);
     }
 }

您还可以决定将StudentRepository实施到新的StudentCustomRepositoryServiceImpl课程。

答案 2 :(得分:3)

JPA 2引入了一个标准API,可用于以编程方式构建查询。

您可以从JpaSpecificationExecutor

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

然后创建客户规范

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

有关详细信息,请参阅此处的春季文档

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

答案 3 :(得分:2)

根据Spring doc HibernateTemplate

  

注意:Hibernate访问代码也可以在普通的Hibernate中编码   样式。因此,对于新开工项目,请考虑采用   标准的Hibernate风格的编码数据访问对象取而代之   在SessionFactory.getCurrentSession()上。这个HibernateTemplate   主要作为基于Hibernate 3的数据的迁移帮助程序存在   访问代码,从Hibernate 4.x中的错误修复中受益。

虽然根据Hibernate doc:

  

新的发展应该集中在JPA上   javax.persistence.criteria.CriteriaQuery API。最终,   特定于Hibernate的标准功能将作为扩展名移植到   JPA javax.persistence.criteria.CriteriaQuery。

因此,最好使用JPQL Criteria:JPA Criteria API Queries

示例:

  CriteriaBuilder cb = entityManager.getCriteriaBuilder();

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

其中entityManager应该是@Autowired。有关详细信息,请参阅上面的链接

答案 4 :(得分:0)

您可以将Query creation引用到spring数据JPA文档中并查看该表,JPA从方法名称创建多个Query创建,您可以避免使用String查询

答案 5 :(得分:0)

使用JPA Criteria创建规范非常复杂,因为API非常详细且非常具有侵略性。

使用Lambda JDK 8,您可以使用简单谓词创建高度非常类型的查询。

@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);
}

您可以隔离条件并在其他查询中重复使用,即规范。

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

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