美文网首页Java 杂谈程序员技术栈
【Java中级】8.5 SSH之Hibernate框架(五)——

【Java中级】8.5 SSH之Hibernate框架(五)——

作者: bobokaka | 来源:发表于2020-02-03 17:54 被阅读0次
    1.0 5.2版本之后过时

    Criteria类涉及Hibernate中QBC查询语句的使用。
    以下内容是官方API文档关于Criteria方面的中文翻译。
    详细参考文章:Hibernate5.2之后QBC查询——createCriteria()等方法过时的解决方法
    官方Hibernate5.2.18 API说明文档:Hibernate ORM 5.2.18.Final User Guide
    以下翻译内容纯靠翻译软件,英文水平不行,见谅。

    image.png
    16.1条。类型化条件查询

    条件查询的类型(也称为<T>)指示查询结果中的预期类型。这可能是实体、整数或任何其他对象。

    16.2条。选择实体

    这可能是最常见的查询形式。应用程序希望选择实体实例。

    例532。选择根实体

        CriteriaBuilder builder = entityManager.getCriteriaBuilder();
        
        CriteriaQuery<Person> criteria = builder.createQuery( Person.class );
        Root<Person> root = criteria.from( Person.class );
        criteria.select( root );
        criteria.where( builder.equal( root.get( Person_.name ), "John Doe" ) );
        
        List<Person> persons = entityManager.createQuery( criteria ).getResultList();
    

    该示例使用createQuery()传入Person类引用,因为查询的结果将是Person对象。

    16.3条。选择表达式

    选择表达式的最简单形式是从实体中选择特定属性。但这个表达式也可能表示一个聚合、一个数学运算等。

    例533。选择属性

        CriteriaBuilder builder = entityManager.getCriteriaBuilder();
        
        CriteriaQuery<String> criteria = builder.createQuery( String.class );
        Root<Person> root = criteria.from( Person.class );
        criteria.select( root.get( Person_.nickName ) );
        criteria.where( builder.equal( root.get( Person_.name ), "John Doe" ) );
        
        List<String> nickNames = entityManager.createQuery( criteria ).getResultList();
    

    在本例中,查询的类型是java.lang.String,因为这是预期的结果类型(Person#nickName属性的类型是java.lang.String)。因为查询可能包含对Person实体的多个引用,所以属性引用始终需要限定。这是通过根get方法调用实现的。

    16.4条。选择多个值

    实际上有几种不同的方法可以使用条件查询选择多个值。我们将在这里探讨两个选项,但推荐的另一种方法是使用元组条件查询中描述的元组,或者考虑包装器查询,有关详细信息,请参阅选择包装器。

    例534。选择数组

        CriteriaBuilder builder = entityManager.getCriteriaBuilder();
        
        CriteriaQuery<Object[]> criteria = builder.createQuery( Object[].class );
        Root<Person> root = criteria.from( Person.class );
        
        Path<Long> idPath = root.get( Person_.id );
        Path<String> nickNamePath = root.get( Person_.nickName);
        
        criteria.select( builder.array( idPath, nickNamePath ) );
        criteria.where( builder.equal( root.get( Person_.name ), "John Doe" ) );
        
        List<Object[]> idAndNickNames = entityManager.createQuery( criteria ).getResultList();
    

    从技术上讲,这被归类为类型化查询,但从处理结果中可以看出,这有点误导人。无论如何,这里的预期结果类型是一个数组。

    然后,该示例使用javax.persistence.CriteriaBuilder的数组方法,该方法将各个选择显式地组合到javax.persistence.criteria.CompoundSelection中。

    例535。使用multiselect选择阵列

        CriteriaBuilder builder = entityManager.getCriteriaBuilder();
        
        CriteriaQuery<Object[]> criteria = builder.createQuery( Object[].class );
        Root<Person> root = criteria.from( Person.class );
        
        Path<Long> idPath = root.get( Person_.id );
        Path<String> nickNamePath = root.get( Person_.nickName);
        
        criteria.multiselect( idPath, nickNamePath );
        criteria.where( builder.equal( root.get( Person_.name ), "John Doe" ) );
        
        List<Object[]> idAndNickNames = entityManager.createQuery( criteria ).getResultList();
    

    正如我们在选择数组中看到的,我们有一个返回对象数组的类型化条件查询。这两个查询在功能上是等价的。第二个示例使用multiselect()方法,该方法的行为与第一次生成条件查询时给定的类型略有不同,但在本例中,它要求选择并返回一个对象[]。

    16.5条。选择包装器

    选择多个值的另一种方法是选择将“包装”多个值的对象。回到这里的示例查询,而不是返回一个[Person#id,Person#nickName]数组,而是声明一个包含这些值的类,并将其用作返回对象。

    例536。选择包装器

        public class PersonWrapper {
        
            private final Long id;
        
            private final String nickName;
        
            public PersonWrapper(Long id, String nickName) {
                this.id = id;
                this.nickName = nickName;
            }
        
            public Long getId() {
                return id;
            }
        
            public String getNickName() {
                return nickName;
            }
        }
        
        
        CriteriaBuilder builder = entityManager.getCriteriaBuilder();
        
        CriteriaQuery<PersonWrapper> criteria = builder.createQuery( PersonWrapper.class );
        Root<Person> root = criteria.from( Person.class );
        
        Path<Long> idPath = root.get( Person_.id );
        Path<String> nickNamePath = root.get( Person_.nickName);
        
        criteria.select( builder.construct( PersonWrapper.class, idPath, nickNamePath ) );
        criteria.where( builder.equal( root.get( Person_.name ), "John Doe" ) );
        
        List<PersonWrapper> wrappers = entityManager.createQuery( criteria ).getResultList();
    

    首先,我们将看到包装器对象的简单定义,我们将使用它来包装我们的结果值。具体来说,请注意构造函数及其参数类型。因为我们将返回PersonWrapper对象,所以我们使用PersonWrapper作为条件查询的类型。

    此示例演示了javax.persistence.CriteriaBuilder方法构造的使用,该构造用于构建包装器表达式。对于结果中的每一行,我们希望通过匹配的构造函数用剩余的参数实例化PersonWrapper。然后将此包装表达式作为select传递。

    16.6条。元组条件查询

    选择多个值的一个更好的方法是使用包装器(我们在选择包装器时刚刚看到)或使用javax.persistence.Tuple契约。

    例537。选择元组

    16.6条。元组条件查询

    选择多个值的一个更好的方法是使用包装器(我们在选择包装器时刚刚看到)或使用javax.persistence.Tuple契约。

    例537。选择元组

        CriteriaBuilder builder = entityManager.getCriteriaBuilder();
        
        CriteriaQuery<Tuple> criteria = builder.createQuery( Tuple.class );
        Root<Person> root = criteria.from( Person.class );
        
        Path<Long> idPath = root.get( Person_.id );
        Path<String> nickNamePath = root.get( Person_.nickName);
        
        criteria.multiselect( idPath, nickNamePath );
        criteria.where( builder.equal( root.get( Person_.name ), "John Doe" ) );
        
        List<Tuple> tuples = entityManager.createQuery( criteria ).getResultList();
        
        for ( Tuple tuple : tuples ) {
            Long id = tuple.get( idPath );
            String nickName = tuple.get( nickNamePath );
        }
        
        //or using indices
        for ( Tuple tuple : tuples ) {
            Long id = (Long) tuple.get( 0 );
            String nickName = (String) tuple.get( 1 );
        }
    

    此示例演示如何通过javax.persistence.Tuple接口访问查询结果。该示例使用javax.persistence.CriteriaBuilder的显式createTupleQuery()。另一种方法是使用createQuery(Tuple.class)。

    我们再次看到multiselect()方法的使用,就像使用multiselect选择数组一样。这里的区别是javax.persistence.CriteriaQuery的类型被定义为javax.persistence.Tuple,因此在本例中,复合选择被解释为Tuple元素。

    Tuple契约提供了三种访问底层元素的形式:

    打字的

    选择元组的示例演示了在tuple.get(idPath)和tuple.get(昵称路径)调用中的这种访问形式。这允许基于用于构建条件的javax.persistence.TupleElement表达式对底层元组值进行类型化访问。

    位置

    允许基于位置访问基础元组值。simple Object get(int position)表单与选择数组和使用multiselect选择数组中所示的访问非常相似。<X>X get(int position,Class<X>类型表单允许类型化位置访问,但基于显式提供的类型,元组值必须是可分配给的类型。

    化名

    允许基于(可选)分配的别名访问基础元组值。示例查询未应用别名。别名将通过javax.persistence.criteria.Selection上的alias方法应用。与位置访问一样,有一个类型化的(Object get(String alias))和一个非类型化的(<X>X get(String alias,Class<X>type form)。

    16.7条。从句

    CriteriaQuery对象定义一个或多个实体、可嵌入或基本抽象模式类型上的查询。查询的根对象是实体,通过导航可以从中访问其他类型。

    -JPA规范,第6.5.2节查询根,第262页

    FROM子句的所有单独部分(根、连接、路径)实现javax.persistence.criteria.FROM接口。

    16.8条。根

    根定义查询中所有连接、路径和属性可用的基础。根始终是实体类型。根由javax.persistence.CriteriaQuery上的重载from方法定义并添加到条件中:

    例538。根方法

        <X> Root<X> from( Class<X> );
        
        <X> Root<X> from( EntityType<X> );
    

    例539。添加根示例

        CriteriaBuilder builder = entityManager.getCriteriaBuilder();
        
        CriteriaQuery<Person> criteria = builder.createQuery( Person.class );
        Root<Person> root = criteria.from( Person.class );
    

    条件查询可以定义多个根,其效果是在新添加的根和其他根之间创建笛卡尔积。下面是一个在个人和合作伙伴实体之间定义笛卡尔积的示例:

    例540。添加多个根示例

        CriteriaBuilder builder = entityManager.getCriteriaBuilder();
        
        CriteriaQuery<Tuple> criteria = builder.createQuery( Tuple.class );
        
        Root<Person> personRoot = criteria.from( Person.class );
        Root<Partner> partnerRoot = criteria.from( Partner.class );
        criteria.multiselect( personRoot, partnerRoot );
        
        Predicate personRestriction = builder.and(
            builder.equal( personRoot.get( Person_.address ), address ),
            builder.isNotEmpty( personRoot.get( Person_.phones ) )
        );
        Predicate partnerRestriction = builder.and(
            builder.like( partnerRoot.get( Partner_.name ), prefix ),
            builder.equal( partnerRoot.get( Partner_.version ), 0 )
        );
        criteria.where( builder.and( personRestriction, partnerRestriction ) );
        
        List<Tuple> tuples = entityManager.createQuery( criteria ).getResultList();
    
    16.9条。连接

    连接允许从其他javax.persistence.criteria.from导航到关联或嵌入属性。连接是由javax.persistence.criteria.From接口的许多重载连接方法创建的。

    例541。连接示例

        CriteriaBuilder builder = entityManager.getCriteriaBuilder();
        
        CriteriaQuery<Phone> criteria = builder.createQuery( Phone.class );
        Root<Phone> root = criteria.from( Phone.class );
        
        // Phone.person is a @ManyToOne
        Join<Phone, Person> personJoin = root.join( Phone_.person );
        // Person.addresses is an @ElementCollection
        Join<Person, String> addressesJoin = personJoin.join( Person_.addresses );
        
        criteria.where( builder.isNotEmpty( root.get( Phone_.calls ) ) );
        
        List<Phone> phones = entityManager.createQuery( criteria ).getResultList();
    
    16.10条。获取

    就像在HQL和JPQL中一样,条件查询可以指定与所有者一起获取关联的数据。回迁是由javax.persistence.criteria.From接口的许多重载回迁方法创建的。

    例542。连接获取示例

        CriteriaBuilder builder = entityManager.getCriteriaBuilder();
        
        CriteriaQuery<Phone> criteria = builder.createQuery( Phone.class );
        Root<Phone> root = criteria.from( Phone.class );
        
        // Phone.person is a @ManyToOne
        Fetch<Phone, Person> personFetch = root.fetch( Phone_.person );
        // Person.addresses is an @ElementCollection
        Fetch<Person, String> addressesJoin = personFetch.fetch( Person_.addresses );
        
        criteria.where( builder.isNotEmpty( root.get( Phone_.calls ) ) );
        
        List<Phone> phones = entityManager.createQuery( criteria ).getResultList();
    

    从技术上讲,嵌入的属性总是与它们的所有者一起获取的。但是,为了定义电话地址的获取,我们需要一个javax.persistence.criteria.Fetch,因为默认情况下元素集合是惰性的。

    使用参数

    例543。参数示例

        CriteriaBuilder builder = entityManager.getCriteriaBuilder();
        
        CriteriaQuery<Person> criteria = builder.createQuery( Person.class );
        Root<Person> root = criteria.from( Person.class );
        
        ParameterExpression<String> nickNameParameter = builder.parameter( String.class );
        criteria.where( builder.equal( root.get( Person_.nickName ), nickNameParameter ) );
        
        TypedQuery<Person> query = entityManager.createQuery( criteria );
        query.setParameter( nickNameParameter, "JD" );
        List<Person> persons = query.getResultList();
    

    使用javax.persistence.CriteriaBuilder的参数方法获取参数引用。然后使用参数引用将参数值绑定到javax.persistence.Query。

    16.13条。使用分组方式

    例544。按示例分组

        CriteriaBuilder builder = entityManager.getCriteriaBuilder();
        
        CriteriaQuery<Tuple> criteria = builder.createQuery( Tuple.class );
        Root<Person> root = criteria.from( Person.class );
        
        criteria.groupBy(root.get("address"));
        criteria.multiselect(root.get("address"), builder.count(root));
        
        List<Tuple> tuples = entityManager.createQuery( criteria ).getResultList();
        
        for ( Tuple tuple : tuples ) {
            String name = (String) tuple.get( 0 );
            Long count = (Long) tuple.get( 1 );
        }
    

    END

    相关文章

      网友评论

        本文标题:【Java中级】8.5 SSH之Hibernate框架(五)——

        本文链接:https://www.haomeiwen.com/subject/ickkxhtx.html