何时使用JPA标准API中的select子句? [英] When to use the select clause in the JPA criteria API?

查看:145
本文介绍了何时使用JPA标准API中的select子句?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述


  1. 不使用 CriteriaQuery#select()

      public List< Address> getAddressOfManager(字符串指定,字符串名称,字符串orderByColumn){

    布尔升序= false;
    CriteriaBuilder cb = emanager.getCriteriaBuilder();
    CriteriaQuery<地址> cq = cb.createQuery(Address.class);
    Root<地址> root = cq.from(Address.class);
    //cq.select(root); < -------------
    加入<地址,员工> employeeAddress = root.join(Address_.employee);
    加入<员工,项目> employeeProject = employeeAddress.join(Employee_.project);
    cq.where(cb.or(cb.equal(employeeProject.get(Project_.name),name),cb.equal(employeeAddress.get(Employee_.designation),designation)));
    订单=升序? cb.asc(root.get(orderByColumn))
    :cb.desc(root.get(orderByColumn));
    cq.orderBy(order);
    列表<地址> result = emanager.createQuery(cq).getResultList();
    返回结果;

    $ / code $ <$ $ $ $ <$ $ $> / code>:

      public List< Address> getAddressOfManager(字符串指定,字符串名称,字符串orderByColumn){

    布尔升序= false;
    CriteriaBuilder cb = emanager.getCriteriaBuilder();
    CriteriaQuery<地址> cq = cb.createQuery(Address.class);
    Root<地址> root = cq.from(Address.class);
    cq.select(root); //< ----------------
    加入<地址,员工> employeeAddress = root.join(Address_.employee);
    加入<员工,项目> employeeProject = employeeAddress.join(Employee_.project);
    cq.where(cb.or(cb.equal(employeeProject.get(Project_.name),name),cb.equal(employeeAddress.get(Employee_.designation),designation)));
    订单=升序? cb.asc(root.get(orderByColumn))
    :cb.desc(root.get(orderByColumn));
    cq.orderBy(order);
    列表<地址> result = emanager.createQuery(cq).getResultList();
    返回结果;
    }

    现在,我很困惑何时使用在JPA标准查询中选择()

  2. p>基本上有两种方法可以在投影术语(或简单地说选择术语) /javaee/7/api/javax/persistence/criteria/CriteriaQuery.htmlrel =noreferrer> CriteriaQuery< T> 界面,其中查询结果将被指定:

      CriteriaQuery< T>选择(选择<?扩展T>选择); 
    CriteriaQuery< T>多选(选择<>选择);

    通常使用的预测术语是候选类( Address 在你的例子中)查询本身。这可能与您的第一个示例中一样隐含。



    第一个示例中的 Address 实体的查询不包含明确地指定了它的投影项,这与在这种情况下显式选择候选类本身是一样的。



    候选持久实体本身作为唯一预测项是隐式推断的。然而,当查询的预计结果是候选持久实体本身以外的其他内容时,可以使用其他几个结构来塑造查询的结果。这些结构可在 CriteriaBuilder



    形成查询结果的方法:

      CompoundSelection< Y> (Class< Y>结果,选择<>术语); 
    CompoundSelection< Object []>数组(选择<>术语);
    CompoundSelection< Tuple>元组(选择<>术语);

    为了保持完整性,我将尝试依次展示它们中的每一个每个人都有一个简单的例子。 construct()



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

      CriteriaQuery< EmployeeDetails> q = cb.createQuery(EmployeeDetails.class); 
    根<员工> root = q.from(Employee.class);
    q.select(cb.construct(EmployeeDetails.class,root.get(Employee_.empName),root.get(Employee_.salary));
    $ b

    EmployeeDetails 在这种情况下,是一个普通的Java类 - 一个非持久性实体,它具有构造函数 String (for empName )和 BigDecimal (for salary )。



    查询返回 List< EmployeeDetails> - 从选定的 Employee s - 持久实体中的非持久实体。



    根据返回的行数,查询也可以使用 EmployeeDetails 例如,/api/javax/persistence/Query.html#getSingleResult()rel =noreferrer> getSingleResult() 方法。

    也可以将多个选择项组合成一个复合选择项,它表示一个 Object [] 元组,如下所示。

    将查询结果转换为 Object []

      CriteriaQuery< Object []> q = cb.createQuery(Object []。class); 
    根<员工> root = q.from(Employee.class);
    q.select(cb.array(root.get(Employee_.empName),root.get(Employee_.salary));
    List< Object []> list = entityManager.createQuery(q) .getResultList();

    可以看出,查询返回一个 List< ; Object []> 。此列表的每个元素都包含一个基于0的数组 Object s - Object [ ]



    将查询结果转换为 Tuple

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

    字符串employeeName = list.get(0).get(empName); //引用由我们它的别名(empName)
    String employeeSalary = list.get(0).get(1); //通过使用索引(薪水)

    引用//遍历列表的元组通过使用别名的foreach循环。 (tuple元组:列表){
    System.out.println(tuple.get(empName)+:+ tuple.get(salary));



    $ / code>

    查询返回一个 List< Tuple> 。由 Tuple 保存的值可以通过基于0的整数索引访问,使用别名 TupleElement 或直接由 TupleElement



    CriteriaBuilder#createTupleQuery()类似于 CriteriaBuilder#createQuery(Tuple.class)



    使用 multiselect( ) 根据结果类型解释条款:
    $ b 输入条款由<$ c $自动解释基于 CriteriaQuery 的结果类型的c> multiselect()
    方法自动到达结果的形状 - 返回类型 CriteriaQuery 问题。例如,这个答案中的第一个例子可以使用 multiselect()重写,如下所示。

      CriteriaQuery中< EmployeeDetails> q = cb.createQuery(EmployeeDetails.class); 
    根<员工> 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的列表), multiselect() code>方法与完全相同的参数将会创建 Tuple 实例,如下所示:

      CriteriaQuery中<元组GT; q = cb.createTupleQuery(); 
    根<员工> root = q.from(Employee.class);
    q.multiselect(root.get(Employee_.empName),root.get(Employee_.salary));

    不用提,但同样的东西也可以重写为返回一个 Object [] (或 Object [] s)列表。

      CriteriaQuery中<对象[]> q = cb.createQuery(Object []。class); 
    根<员工> root = q.from(Employee.class);
    q.multiselect(root.get(Employee_.empName),root.get(Employee_.salary));

    在这两种情况下, muliselect()方法根据查询的返回类型自动解释其参数投影术语,如前所述,它是 Tuple Object []



    还应该注意的是,EcliseLink有一个 bug ,这样在使用<$ c获取单个布尔选择项时仍有待修复$ c> multiselect(),如这个问题 所示。






    根据不同的JPA提供者, multiselect()方法的行为会得到更多有趣的是 Object 作为结果类型,


    • 如果 multiselect()方法与单个选择项一起使用,返回类型是所选的词本身。

    • 但是,如果 multiselect()方法包含多个输入项/选项/投影项,则结果类型为 Object []



    我不太确定不同的提供者,但是 multiselect()方法可能不是数组或集合(或元组值)。可以被允许为 multiselect()参数的唯一复合项是由构造()方法创建的项它基本上代表一个单一元素。




    除上述结构外, CriteriaQuery在使用标量/组/集合/单值函数(如 count())时,#select(Selection< ;? extends T>选择) code>, max() min()等和子查询。


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

      CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); 

    //计算总员工数
    CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
    根员工= criteriaQuery.from(Employee.class);
    criteriaQuery.select(criteriaBuilder.count(employee)); //< ------
    Query query = entityManager.createQuery(criteriaQuery);
    Long结果= query.getSingleResult();

    //最高工资
    CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
    根员工= criteriaQuery.from(Employee.class);
    criteriaQuery.select(criteriaBuilder.max(employee.get(salary)); //< ------
    Query query = entityManager.createQuery(criteriaQuery);
    Long result = query.getSingleResult();


    http://en.wikibooks.org/wiki/Java_Persistence/Criteria#Selection


    1. Without using 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. With 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;
      }
      

      Now, I am confused as to when to use select() in JPA criteria query.

    解决方案

    There are basically two ways to specify the projection term (or simply saying the selection term) on the CriteriaQuery<T> interface in which the query result is to be specified :

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

    Often the projection term used is the candidate class (Address in your examples) of the query itself. It may be implicit as in your first example.

    The query from the Address entity in your first example does not explicitly specify its projection term and it is the same as explicitly selecting the candidate class itself in this case.

    A candidate persistent entity itself as the only projection term is implicitly inferred.


    When the projected result of the query is however, something other than the candidate persistent entity itself, several other constructs are available to shape the result of the query. These constructs are available in the CriteriaBuilder interface.

    Methods to shape query result :

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

    For the sake of completeness only, I will try to demonstrate each of them in turn with a simple example for each of them.


    Shaping query result into instances of a class (a non persistent entity) by construct():

    The construct() method creates an instance of the given class argument and invokes a constructor (of a non-persistent entity) with values from the input selection terms. These arguments to the constructor of a non-persistent entity (not even an entity, a plain Java class) must match in number, order and type (datatype) with values corresponding to the input selection terms, for example.

    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 in this case, is a plain Java class -- a non-persistent entity that has a constructor which takes two parameters of type String (for empName) and BigDecimal (for salary).

    The query returns a List<EmployeeDetails> -- a non-persistent entity from the selected Employees -- a persistent entity.

    Depending upon the number of rows returned, the query may also return EmployeeDetails using the getSingleResult() method, for example.

    Multiple selection items can also be combined into a compound selection term that represents an Object[] or Tuple as shown below.

    Shaping query result into an 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();
    

    As can be seen, the query returns a List<Object[]>. Each element of this list contains a 0-based array of Objects - Object[].

    Shaping query result into a Tuple :

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

    The query returns a List<Tuple>. The values held by a Tuple are accessible by a 0-based integer index, using an alias name of the TupleElement or directly by the TupleElement.

    CriteriaBuilder#createTupleQuery() is analogous to CriteriaBuilder#createQuery(Tuple.class).

    Using multiselect() to interpret terms based on result type :

    Input terms are automatically interpreted by the multiselect() method based on the result type of the CriteriaQuery to automatically arrive at the shape of the result -- the return type of the CriteriaQuery in question. For example, the very first example in this answer could be rewritten using multiselect() as follows.

    CriteriaQuery<EmployeeDetails> q = cb.createQuery(EmployeeDetails.class);
    Root<Employee> root = q.from(Employee.class);
    q.multiselect(root.get(Employee_.empName), root.get(Employee_.salary));
    

    Since the type of the result is EmployeeDetails, the multiselect() method interprets its argument projection terms as constructor arguments of EmployeeDetails.

    Notice that a construct like this, cb.construct(EmployeeDetails.class, root.get(Employee_.empName), root.get(Employee_.salary) as used in the first example, does not have to be used in the preceding example using multiselect() which automatically interprets its argument projection terms based on the return type of the query and invokes an appropriate constructor in the result class - EmployeeDetails.

    If the query were to be specified to return a Tuple (or a list of Tuples), the multiselect() method with the exact same arguments would create Tuple instances instead as shown below.

    CriteriaQuery<Tuple> q = cb.createTupleQuery();
    Root<Employee> root = q.from(Employee.class);
    q.multiselect(root.get(Employee_.empName), root.get(Employee_.salary));
    

    Needless to mention but the same thing can also be rewritten to return an Object[] (or a list of Object[]s).

    CriteriaQuery<Object[]> q = cb.createQuery(Object[].class);
    Root<Employee> root = q.from(Employee.class);
    q.multiselect(root.get(Employee_.empName), root.get(Employee_.salary));
    

    In both the cases, the muliselect() method automatically interprets its argument projection terms based on the return type of the query as said earlier which is Tuple and Object[] respectively.

    It should also be noted that EcliseLink has a bug which is still to be fixed while fetching a single Boolean selection term in this way using multiselect() as shown in this question.


    Depending upon different JPA providers, the behaviour of the multiselect() method gets more interesting with Object as a result type,

    • If the multiselect() method is used with a single selection term, the return type is the selected term itself.
    • If the multiselect() method however, contains more than one input term/selection term/projection term, the result type is Object[].

    I am not quite sure about different providers but the selection terms as specified by the multiselect() method may not be an array or a collection (or a tuple-valued compound term). The only compound terms which may be allowed as multiselect() arguments are those which are created by the construct() method which essentially represents a single element in turn.


    In addition to the above constructs, the usage of CriteriaQuery#select(Selection<? extends T> selection) is quite common while using scalar / group / aggregate / single-valued functions such as count(), max(), min() etc and sub-queries. The usage of sub-queries is excluded from this answer for brevity.

    A Selection defines what is selected by a query. A Selection can be any object expression, attribute expression, function, sub-select, constructor or aggregation function. An alias can be defined for a Selection using the alias() API.

    CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
    
    // Count the total employees
    CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
    Root employee = criteriaQuery.from(Employee.class);
    criteriaQuery.select(criteriaBuilder.count(employee)); //<------
    Query query = entityManager.createQuery(criteriaQuery);
    Long result = query.getSingleResult();
    
    // Maximum salary
    CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
    Root employee = criteriaQuery.from(Employee.class);
    criteriaQuery.select(criteriaBuilder.max(employee.get("salary")); //<------
    Query query = entityManager.createQuery(criteriaQuery);
    Long result = query.getSingleResult();
    

    http://en.wikibooks.org/wiki/Java_Persistence/Criteria#Selection

    这篇关于何时使用JPA标准API中的select子句?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆