Hibernate与PostgreSQL DB一起使用,当按列排序desc时,将null值设置为高于非null值。
SQL99标准提供关键字“NULLS LAST”来声明空值应该低于非空值。
使用Hibernate的Criteria API可以实现“NULLS LAST”行为吗?
答案 0 :(得分:43)
此功能已在Hibernate 4.2.x和4.3.x版本中实现,如前所述。
它可以用作例如:
Criteria criteria = ...;
criteria.addOrder( Order.desc( "name" ).nulls(NullPrecedence.FIRST) );
Hibernate v4.3 javadocs不太遗漏here。
答案 1 :(得分:15)
鉴于HHH-465没有修复,并且由于Steve Ebersole给出的理由不会在不久的将来得到修复,你最好的选择是使用问题所附的CustomNullsFirstInterceptor
全局或专门用于更改SQL语句。
我在下面为读者发帖(Emilio Dolce的作品):
public class CustomNullsFirstInterceptor extends EmptyInterceptor {
private static final long serialVersionUID = -3156853534261313031L;
private static final String ORDER_BY_TOKEN = "order by";
public String onPrepareStatement(String sql) {
int orderByStart = sql.toLowerCase().indexOf(ORDER_BY_TOKEN);
if (orderByStart == -1) {
return super.onPrepareStatement(sql);
}
orderByStart += ORDER_BY_TOKEN.length() + 1;
int orderByEnd = sql.indexOf(")", orderByStart);
if (orderByEnd == -1) {
orderByEnd = sql.indexOf(" UNION ", orderByStart);
if (orderByEnd == -1) {
orderByEnd = sql.length();
}
}
String orderByContent = sql.substring(orderByStart, orderByEnd);
String[] orderByNames = orderByContent.split("\\,");
for (int i=0; i<orderByNames.length; i++) {
if (orderByNames[i].trim().length() > 0) {
if (orderByNames[i].trim().toLowerCase().endsWith("desc")) {
orderByNames[i] += " NULLS LAST";
} else {
orderByNames[i] += " NULLS FIRST";
}
}
}
orderByContent = StringUtils.join(orderByNames, ",");
sql = sql.substring(0, orderByStart) + orderByContent + sql.substring(orderByEnd);
return super.onPrepareStatement(sql);
}
}
答案 2 :(得分:5)
您可以在hibernate属性中配置“nulls first”/“nulls last”,以便默认情况下通过任何条件调用来选择它:hibernate.order_by.default_null_ordering=last
(或=first
)。
有关详细信息,请参阅this hibernate commit。
答案 3 :(得分:2)
这是我对班级的更新(Pascal Thivent):
for (int i = 0; i < orderByNames.length; i++) {
if (orderByNames[i].trim().length() > 0) {
String orderName = orderByNames[i].trim().toLowerCase();
if (orderName.contains("desc")) {
orderByNames[i] = orderName.replace("desc", "desc NULLS LAST");
} else {
orderByNames[i] = orderName.replace("asc", "asc NULLS FIRST");
}
}
}
这解决了问题:
如果sql在订购后有限制/偏移,则会中断 - Sathish 2011年4月1日14:52
此外,您还可以在JPA(休眠)中使用它:
Session session = entityManager.unwrap(Session.class);
Session nullsSortingProperlySession = null;
try {
// perform a query guaranteeing that nulls will sort last
nullsSortingProperlySession = session.getSessionFactory().withOptions()
.interceptor(new GuaranteeNullsFirstInterceptor())
.openSession();
} finally {
// release the session, or the db connections will spiral
try {
if (nullsSortingProperlySession != null) {
nullsSortingProperlySession.close();
}
} catch (Exception e) {
logger.error("Error closing session", e);
}
}
我已经在postgres上测试了它,它修复了我们所拥有的'nulls高于非nulls'问题。
答案 4 :(得分:2)
另一种变体,如果您动态创建SQL并且不使用Criteria API:
COALESCE(,'0')[ASC | DESC]
这适用于varchar或数字列。
答案 5 :(得分:1)
我们可以使用以下 Sort 参数创建 Pageable 对象:
JpaSort.unsafe(Sort.Direction.ASC, "ISNULL(column_name), (column_name)")
我们也可以准备HQL:
String hql = "FROM EntityName e ORDER BY e.columnName NULLS LAST";
答案 6 :(得分:0)