何时在JPA标准API中使用select子句?

时间:2015-05-17 18:53:59

标签: hibernate jpa criteria criteria-api

  1. 不使用CriteriaQuery#select()

    public List<Address> getAddressOfManager(String designation, String name, String orderByColumn) {
    
        Boolean ascending = false;
        CriteriaBuilder cb = emanager.getCriteriaBuilder();
        CriteriaQuery<Address> cq = cb.createQuery(Address.class);
        Root<Address> root = cq.from(Address.class);
        //cq.select(root);  <-------------
        Join<Address, Employee> employeeAddress = root.join(Address_.employee);
        Join<Employee,Project> employeeProject = employeeAddress.join(Employee_.project);
        cq.where(cb.or(cb.equal(employeeProject.get(Project_.name), name),cb.equal(employeeAddress.get(Employee_.designation), designation)));
        Order order = ascending ? cb.asc(root.get(orderByColumn))
                : cb.desc(root.get(orderByColumn));
        cq.orderBy(order);
        List<Address> result = emanager.createQuery(cq).getResultList();
        return result;
    }
    
  2. 使用CriteriaQuery#select()

    public List<Address> getAddressOfManager(String designation, String name, String orderByColumn) {
    
        Boolean ascending = false;
        CriteriaBuilder cb = emanager.getCriteriaBuilder();
        CriteriaQuery<Address> cq = cb.createQuery(Address.class);
        Root<Address> root = cq.from(Address.class);
        cq.select(root); //<----------------
        Join<Address, Employee> employeeAddress = root.join(Address_.employee);
        Join<Employee,Project> employeeProject = employeeAddress.join(Employee_.project);
        cq.where(cb.or(cb.equal(employeeProject.get(Project_.name), name),cb.equal(employeeAddress.get(Employee_.designation), designation)));
        Order order = ascending ? cb.asc(root.get(orderByColumn))
                : cb.desc(root.get(orderByColumn));
        cq.orderBy(order);
        List<Address> result = emanager.createQuery(cq).getResultList();
        return result;
    }
    

    现在,我对在JPA条件查询中何时使用select()感到困惑。

1 个答案:

答案 0 :(得分:14)

基本上有两种方法可以在查询结果所在的CriteriaQuery<T>界面上指定投影词(或简单地说选择词)指定:

CriteriaQuery<T> select(Selection<? extends T> selection);
CriteriaQuery<T> multiselect(Selection<?>... selections);

通常使用的投影术语是查询本身的候选类(示例中为Address)。它可能隐含在你的第一个例子中。

第一个示例中来自Address实体的查询没有明确指定其投影术语,它与在这种情况下明确选择候选类本身相同。

隐式推断候选持久性实体本身作为唯一的投影术语。

但是,当查询的预测结果是候选持久性实体本身以外的其他内容时,可以使用其他几种结构来形成查询结果。这些结构可在CriteriaBuilder界面中找到。

对查询结果进行整形的方法:

CompoundSelection<Y> construct(Class<Y> result, Selection<?>... terms);
CompoundSelection<Object[]> array(Selection<?>... terms);
CompoundSelection<Tuple> tuple(Selection<?>... terms);

为了完整起见,我将尝试依次为每一个示例演示每一个。

construct()将查询结果整形为类(非持久性实体)的实例:

construct()方法创建给定类参数的实例,并使用输入选择项中的值调用(非持久实体的)构造函数。例如,非持久性实体(甚至不是实体,普通Java类)的构造函数的这些参数必须在数量,顺序和类型(数据类型)上与对应于输入选择项的值匹配。

CriteriaQuery<EmployeeDetails> q = cb.createQuery(EmployeeDetails.class);
Root<Employee> root = q.from(Employee.class);
q.select(cb.construct(EmployeeDetails.class, root.get(Employee_.empName), root.get(Employee_.salary));
在这种情况下,

EmployeeDetails是一个普通的Java类 - 一个非持久化实体,它有一个构造函数,它接受String类型的两个参数(对于empName)和{{ 1}}(对于BigDecimal)。

查询返回salary - 来自所选List<EmployeeDetails> s的非持久性实体 - 持久性实体。

根据返回的行数,查询也可能使用getSingleResult()方法返回Employee,例如。

多个选择项也可以组合成一个复合选择词,代表EmployeeDetailsObject[],如下所示。

将查询结果整形为Tuple

Object[]

可以看出,查询返回CriteriaQuery<Object[]> q = cb.createQuery(Object[].class); Root<Employee> root = q.from(Employee.class); q.select(cb.array(root.get(Employee_.empName), root.get(Employee_.salary)); List<Object[]> list = entityManager.createQuery(q).getResultList(); 。此列表的每个元素都包含一个基于0的List<Object[]> s - Object数组。

将查询结果整形为Tuple

Object[]

查询返回CriteriaQuery<Tuple> q = cb.createTupleQuery(); Root<Employee> root = q.from(Employee.class); Selection<String> empName = root.get(Employee_.empName).alias("empName"); q.select(cb.tuple(empName, root.get(Employee_.salary).alias("salary"); List<Tuple> list = entityManager.createQuery(q).getResultList(); String employeeName = list.get(0).get("empName");//Referring to by using its alias (empName) String employeeSalary = list.get(0).get(1);//Referring to by using its index (salary) //Iterate over a list of tuples through a foreach loop using alias. for (Tuple tuple : list) { System.out.println(tuple.get("empName") + " : " + tuple.get("salary")); } List<Tuple>保存的值可通过基于0的整数索引访问,使用别名TupleElement或直接Tuple

TupleElement类似于CriteriaBuilder#createTupleQuery()

使用multiselect()根据结果类型解释字词:

CriteriaBuilder#createQuery(Tuple.class)方法会根据multiselect()的结果类型自动解释输入字词,以自动达到结果的形状 - CriteriaQuery的返回类型题。例如,可以使用CriteriaQuery重写此答案中的第一个示例,如下所示。

multiselect()

由于结果的类型为CriteriaQuery<EmployeeDetails> q = cb.createQuery(EmployeeDetails.class); Root<Employee> root = q.from(Employee.class); q.multiselect(root.get(Employee_.empName), root.get(Employee_.salary)); EmployeeDetails方法将其参数投影项解释为multiselect()的构造函数参数。

请注意,第一个示例中使用的此类构造EmployeeDetails不必在前面的示例中使用cb.construct(EmployeeDetails.class, root.get(Employee_.empName), root.get(Employee_.salary),它会根据返回类型自动解释其参数投影术语查询并在结果类中调用适当的构造函数 - multiselect()

如果要指定查询以返回EmployeeDetails(或Tuple s的列表),则Tuple方法具有完全相同的参数将创建multiselect()例如,如下所示。

Tuple

不用说,但同样的事情也可以重写,以返回CriteriaQuery<Tuple> q = cb.createTupleQuery(); Root<Employee> root = q.from(Employee.class); q.multiselect(root.get(Employee_.empName), root.get(Employee_.salary)); (或Object[] s的列表。)

Object[]

在这两种情况下,CriteriaQuery<Object[]> q = cb.createQuery(Object[].class); Root<Employee> root = q.from(Employee.class); q.multiselect(root.get(Employee_.empName), root.get(Employee_.salary)); 方法都会根据前面提到的查询的返回类型自动解释其参数投影术语,分别为muliselect()Tuple

还应该注意的是,EcliseLink有一个bug,在使用Object[]以这种方式获取单个Boolean选择术语时仍需要修复,如{ {3}}

根据不同的JPA提供程序,multiselect()方法的行为会因multiselect()作为结果类型而变得更有趣,

  • 如果Object方法与单个选择术语一起使用,则返回类型是所选术语本身。
  • 但是,如果multiselect()方法包含多个输入字词/选择字词/投影字词,则结果类型为multiselect()

我不太确定不同的提供者,但Object[]方法指定的选择术语可能不是数组或集合(或元组值复合词)。可以作为multiselect()参数允许的唯一复合术语是由multiselect()方法创建的,它们基本上代表单个元素。

除了上述结构之外,this question的使用在使用标量/组/聚合/单值函数时很常见,例如construct()count(),{{1等等和子查询。为简洁起见,从这个答案中排除了子查询的使用。

  

max()定义查询选择的内容。选择可以   任何对象表达式,属性表达式,函数,子选择,   构造函数或聚合函数。可以为a定义别名   min()使用alias()API。

Selection

CriteriaQuery#select(Selection<? extends T> selection)