使用Hibernate排序


1.概述

本文演示了如何使用Hibernate查询语言(HQL)和Criteria API对Hibernate 进行排序。

2.使用HQL排序

使用Hibernate的HQL排序就像将Order By子句添加到HQL查询字符串一样简单:

String hql = "FROM Foo f ORDER BY f.name";
Query query = sess.createQuery(hql);

执行此代码后,Hibernate将生成以下SQL查询:

Hibernate: select foo0_.ID as ID1_0_, foo0_.NAME as NAME2_0_ from
    FOO foo0_ order by foo0_.NAME

默认排序顺序方向为升序。这就是生成的SQL查询中不包含订单条件asc的原因。

2.1。使用显式排序顺序

要手动指定排序顺序,您需要在HQL查询字符串中包含订单方向:

String hql = "FROM Foo f ORDER BY f.name ASC";
Query query = sess.createQuery(hql);

在此示例中,在HQL中设置asc子句包含在生成的SQL查询中:

Hibernate: select foo0_.ID as ID1_0_, foo0_.NAME as NAME2_0_
    from FOO foo0_ order by foo0_.NAME ASC

2.2。按多个属性排序

可以将多个属性以及可选的排序顺序添加到HQL查询字符串中的Order By子句:

String hql = "FROM Foo f ORDER BY f.name DESC, f.id ASC";
Query query = sess.createQuery(hql);

生成的SQL查询将相应更改:

Hibernate: select foo0_.ID as ID1_0_, foo0_.NAME as NAME2_0_
    from FOO foo0_ order by foo0_.NAME DESC, foo0_.ID ASC

2.3。设置空值的排序优先级

默认情况下,当sort by属性具有空值时,由RDMS决定优先级。这种默认的处理可以通过将覆盖一个NULLS FIRST或NULLS LAST在HQL查询字符串条款。

这个简单的示例将任何空值放在结果列表的末尾:

String hql = "FROM Foo f ORDER BY f.name NULLS LAST";
Query query = sess.createQuery(hql);

让我们在生成的SQL查询中看到is null then 1 else 0子句:

Hibernate: select foo0_.ID as ID1_1_, foo0_.NAME as NAME2_1_,
foo0_.BAR_ID as BAR_ID3_1_, foo0_.idx as idx4_1_ from FOO foo0_
order by case when foo0_.NAME is null then 1 else 0 end, foo0_.NAME

2.4。排序一对多关系

让我们分析一个复杂的排序案例:以一对多关系排序实体 - 包含Foo实体集合的Bar。

我们将通过使用Hibernate @OrderBy注释来注释集合来完成此操作; 我们将指定完成排序的字段以及方向:

@OrderBy(clause = "NAME DESC")
Set<Foo> fooList = new HashSet();

注意注释的子句参数。与类似的@OrderBy JPA注释相比,这是Hibernate的@OrderBy独有的。将此方法与其JPA等价物区分开的另一个特征是,子句参数表示排序是基于FOO表的NAME列完成的,而不是基于Foo的name属性。

现在让我们看一下Bars和Foos的实际排序:

String hql = "FROM Bar b ORDER BY b.id";
Query query = sess.createQuery(hql);

将得到的SQL语句表明排序Foo的放置在fooList:

Hibernate: select bar0_.ID as ID1_0_, bar0_.NAME as NAME2_0_ from BAR bar0_
    order by bar0_.ID Hibernate: select foolist0_.BAR_ID as BAR_ID3_0_0_,
    foolist0_.ID as ID1_1_0_, foolist0_.ID as ID1_1_1_, foolist0_.NAME as
    NAME2_1_1_, foolist0_.BAR_ID as BAR_ID3_1_1_, foolist0_.idx as idx4_1_1_
    from FOO foolist0_ where foolist0_.BAR_ID=? order by foolist0_.NAME desc

要记住的一件事是,不可能像JPA那样对列表进行排序。Hibernate文档说明:

Hibernate currently ignores @OrderBy on @ElementCollection on e.g. List<String>. The order of elements is as returned by the database, undefined.

作为旁注,可以通过使用Hibernate的旧XML配置,并用<Bag ...>元素替换<List ..>元素来解决此限制。

3.使用Hibernate Criteria进行排序

Criteria Object API提供Order类作为管理排序的主要API。

3.1。设置排序顺序

该订单类有两个方法来设置排序顺序:

  • asc(String attribute):按属性按升序对查询进行排序。
  • desc(String attribute):按属性降序排序查询。

让我们从一个简单的例子开始 - 按单个id属性排序:

Criteria criteria = sess.createCriteria(Foo.class, "FOO");
criteria.addOrder(Order.asc("id"));

请注意,asc方法的参数区分大小写,并且应该与要排序的属性的名称匹配。

Hibernate Criteria的Object API显式设置排序顺序方向,这反映在代码生成的SQL语句中:

Hibernate: select this_.ID as ID1_0_0_, this_.NAME as NAME2_0_0_
    from FOO this_ order by this_.ID sac

3.2。按多个属性排序

按多个属性排序只需要将Order对象添加到Criteria实例,如下例所示:

Criteria criteria = sess.createCriteria(Foo.class, "FOO");
criteria.addOrder(Order.asc("name"));
criteria.addOrder(Order.asc("id"));

在SQL中生成的查询是:

Hibernate: select this_.ID as ID1_0_0_, this_.NAME as NAME2_0_0_ from
    FOO this_ order by this_.NAME asc, this_.ID sac

3.3。设置空值的排序优先级

默认情况下,当sort by属性具有空值时,由RDMS决定优先级。Hibernate Criteria Object API可以很容易地更改默认值并将空值放在升序有序列表的末尾:

Criteria criteria = sess.createCriteria(Foo.class, "FOO");
criteria.addOrder(Order.asc("name").nulls(NullPrecedence.LAST));

这是基础SQL查询 - 使用is null然后是1 else 0子句:

Hibernate: select this_.ID as ID1_1_1_, this_.NAME as NAME2_1_1_,
    this_.BAR_ID as BAR_ID3_1_1_, this_.idx as idx4_1_1_, bar2_.ID as
    ID1_0_0_, bar2_.NAME as NAME2_0_0_ from FOO order by case when
    this_.NAME is null then 1 else 0 end, this_.NAME asc

或者,我们也可以将空值放在降序有序列表的开头:

Criteria criteria = sess.createCriteria(Foo.class, "FOO");
criteria.addOrder(Order.desc("name").nulls(NullPrecedence.FIRST));

相应的SQL查询如下 - 使用is null然后是0 else 1子句:

Hibernate: select this_.ID as ID1_1_1_, this_.NAME as NAME2_1_1_,
    this_.BAR_ID as BAR_ID3_1_1_, this_.idx as idx4_1_1_, bar2_.ID as
    ID1_0_0_, bar2_.NAME as NAME2_0_0_ from FOO order by case when
    this_.NAME is null then 0 else 1 end, this_.NAME desc

需要注意的是,如果要排序的属性是基本类型像一个INT,一个PresisitenceException将抛出。

例如,如果f.anIntVariable的值为null,则执行查询:

String jql = "Select f from Foo as f order by f.anIntVariable desc NULLS FIRST";
Query sortQuery = entityManager.createQuery(jql);

将抛出:

javax.persistence.PersistenceException: org.hibernate.PropertyAccessException:
Null value was assigned to a property of primitive type setter of
com.cc.jpa.example.Foo.anIntVariable