14.13. HQL示例

Hibernate查询可以非常的强大与复杂。实际上,Hibernate的一个主要卖点就是查询语句的威力。这里有一些例子,它们与我在最近的 一个项目中使用的查询非常相似。注意你能用到的大多数查询比这些要简单的多!

下面的查询对于某个特定的客户的所有未支付的账单,在给定给最小总价值的情况下,返回订单的id,条目的数量和总价值, 返回值按照总价值的结果进行排序。为了决定价格,查询使用了当前目录。作为转换结果的SQL查询,使用了ORDER, ORDER_LINE, PRODUCT, CATALOGPRICE 库表。

  1. select order.id, sum(price.amount), count(item)
  2. from Order as order
  3. join order.lineItems as item
  4. join item.product as product,
  5. Catalog as catalog
  6. join catalog.prices as price
  7. where order.paid = false
  8. and order.customer = :customer
  9. and price.product = product
  10. and catalog.effectiveDate < sysdate
  11. and catalog.effectiveDate >= all (
  12. select cat.effectiveDate
  13. from Catalog as cat
  14. where cat.effectiveDate < sysdate
  15. )
  16. group by order
  17. having sum(price.amount) > :minAmount
  18. order by sum(price.amount) desc

这简直是一个怪物!实际上,在现实生活中,我并不热衷于子查询,所以我的查询语句看起来更像这个:

  1. select order.id, sum(price.amount), count(item)
  2. from Order as order
  3. join order.lineItems as item
  4. join item.product as product,
  5. Catalog as catalog
  6. join catalog.prices as price
  7. where order.paid = false
  8. and order.customer = :customer
  9. and price.product = product
  10. and catalog = :currentCatalog
  11. group by order
  12. having sum(price.amount) > :minAmount
  13. order by sum(price.amount) desc

下面一个查询计算每一种状态下的支付的数目,除去所有处于AWAITING_APPROVAL状态的支付,因为在该状态下 当前的用户作出了状态的最新改变。该查询被转换成含有两个内连接以及一个相关联的子选择的SQL查询,该查询使用了表 PAYMENT, PAYMENT_STATUS 以及 PAYMENT_STATUS_CHANGE

  1. select count(payment), status.name
  2. from Payment as payment
  3. join payment.currentStatus as status
  4. join payment.statusChanges as statusChange
  5. where payment.status.name <> PaymentStatus.AWAITING_APPROVAL
  6. or (
  7. statusChange.timeStamp = (
  8. select max(change.timeStamp)
  9. from PaymentStatusChange change
  10. where change.payment = payment
  11. )
  12. and statusChange.user <> :currentUser
  13. )
  14. group by status.name, status.sortOrder
  15. order by status.sortOrder

如果我把statusChanges实例集映射为一个列表(list)而不是一个集合(set), 书写查询语句将更加简单.

  1. select count(payment), status.name
  2. from Payment as payment
  3. join payment.currentStatus as status
  4. where payment.status.name <> PaymentStatus.AWAITING_APPROVAL
  5. or payment.statusChanges[ maxIndex(payment.statusChanges) ].user <> :currentUser
  6. group by status.name, status.sortOrder
  7. order by status.sortOrder

下面一个查询使用了MS SQL Server的 isNull()函数用以返回当前用户所属组织的组织帐号及组织未支付的账。 它被转换成一个对表ACCOUNT, PAYMENT, PAYMENT_STATUS, ACCOUNT_TYPE, ORGANIZATION 以及 ORG_USER进行的三个内连接, 一个外连接和一个子选择的SQL查询。

  1. select account, payment
  2. from Account as account
  3. left outer join account.payments as payment
  4. where :currentUser in elements(account.holder.users)
  5. and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)
  6. order by account.type.sortOrder, account.accountNumber, payment.dueDate

对于一些数据库,我们需要弃用(相关的)子选择。

  1. select account, payment
  2. from Account as account
  3. join account.holder.users as user
  4. left outer join account.payments as payment
  5. where :currentUser = user
  6. and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)
  7. order by account.type.sortOrder, account.accountNumber, payment.dueDate