⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hibernate2 参考文档之十.txt

📁 Hibernate使用说明书
💻 TXT
📖 第 1 页 / 共 2 页
字号:

from eg.Player p where 3 > all elements(p.scores)

from eg.Show show where 'fizard' in indices(show.acts)
请注意这些设施:size,elements,indices,minIndex,maxIndex,minElement,maxElement 都有一些使用限制: 

在where子句中: 只对支持子查询的数据库有效 

在select子句中:只有elements和indices有效 

有序的集合(数组、list、map)的元素可以用索引来进行引用(只限于在where子句中) 

from Order order where order.items[0].id = 1234

select person from Person person, Calendar calendar
where calendar.holidays['national day'] = person.birthDay
    and person.nationality.calendar = calendar

select item from Item item, Order order
where order.items[ order.deliveredItemIndices[0] ] = item and order.id = 11

select item from Item item, Order order
where order.items[ maxindex(order.items) ] = item and order.id = 11
[]中的表达式允许是另一个数学表达式。 

select item from Item item, Order order
where order.items[ size(order.items) - 1 ] = item
HQL也对一对多关联或者值集合提供内置的index()函数。 

select item, index(item) from Order order 
    join order.items item
where index(item) < 5
底层数据库支持的标量SQL函数也可以使用 

from eg.DomesticCat cat where upper(cat.name) like 'FRI%'
假如以上的这些还没有让你信服的话,请想象一下下面的查询假若用SQL来写,会变得多么长,多么不可读: 

select cust
from Product prod,
    Store store
    inner join store.customers cust
where prod.name = 'widget'
    and store.location.name in ( 'Melbourne', 'Sydney' )
    and prod = all elements(cust.currentOrder.lineItems)
提示:对应的SQL语句可能是这样的 

SELECT cust.name, cust.address, cust.phone, cust.id, cust.current_order
FROM customers cust,
    stores store,
    locations loc,
    store_customers sc,
    product prod
WHERE prod.name = 'widget'
    AND store.loc_id = loc.id
    AND loc.name IN ( 'Melbourne', 'Sydney' )
    AND sc.store_id = store.id
    AND sc.cust_id = cust.id
    AND prod.id = ALL(
        SELECT item.prod_id
        FROM line_items item, orders o
        WHERE item.order_id = o.id
            AND cust.current_order = o.id
    )
10.9. order by 子句
查询返回的列表可以按照任何返回的类或者组件的属性排序: 

from eg.DomesticCat cat
order by cat.name asc, cat.weight desc, cat.birthdate
asc和desc是可选的,分别代表升序或者降序。 

10.10. group by 子句
返回统计值的查询可以按照返回的类或者组件的任何属性排序: 

select cat.color, sum(cat.weight), count(cat) 
from eg.Cat cat
group by cat.color

select foo.id, avg( elements(foo.names) ), max( indices(foo.names) ) 
from eg.Foo foo
group by foo.id
请注意:你可以在select子句中使用elements和indices指令,即使你的数据库不支持子查询也可以。 

having子句也是允许的。 

select cat.color, sum(cat.weight), count(cat) 
from eg.Cat cat
group by cat.color 
having cat.color in (eg.Color.TABBY, eg.Color.BLACK)
在having子句中允许出现SQL函数和统计函数,当然这需要底层数据库支持才行。(比如说,MySQL就不支持) 

select cat
from eg.Cat cat
    join cat.kittens kitten
group by cat
having avg(kitten.weight) > 100
order by count(kitten) asc, sum(kitten.weight) desc
注意,group by子句和order by子句都不支持数学表达式。 

10.11. 子查询
对于支持子查询的数据库来说,Hibernate支持在查询中嵌套子查询。子查询必须由圆括号包围(常常是在一个SQL统计函数中)。也允许关联子查询(在外部查询中作为一个别名出现的子查询)。 

from eg.Cat as fatcat 
where fatcat.weight > ( 
    select avg(cat.weight) from eg.DomesticCat cat 
)

from eg.DomesticCat as cat 
where cat.name = some ( 
    select name.nickName from eg.Name as name 
)
    
from eg.Cat as cat 
where not exists ( 
    from eg.Cat as mate where mate.mate = cat 
)

from eg.DomesticCat as cat 
where cat.name not in ( 
    select name.nickName from eg.Name as name 
)
10.12. 示例
Hibernate查询可以非常强大复杂。实际上,强有力的查询语言是Hibernate的主要卖点之一。下面给出的示例与我在近期实际项目中使用的一些查询很类似。请注意你编写的查询大部分等都不会这么复杂! 

下面的查询对特定的客户,根据给定的最小总计值(minAmount),查询出所有未付订单,返回其订单号、货品总数、订单总金额,结果按照总金额排序。在决定价格的时候,参考当前目录。产生的SQL查询,在ORDER,ORDER_LINE,PRODUCT,CATALOG和PRICE表之间有四个内部连接和一个没有产生关联的字查询。 

select order.id, sum(price.amount), count(item)
from Order as order
    join order.lineItems as item
    join item.product as product,
    Catalog as catalog
    join catalog.prices as price
where order.paid = false
    and order.customer = :customer
    and price.product = product
    and catalog.effectiveDate < sysdate
    and catalog.effectiveDate >= all (
        select cat.effectiveDate 
        from Catalog as cat
        where cat.effectiveDate < sysdate
    )
group by order
having sum(price.amount) > :minAmount
order by sum(price.amount) desc
好家伙,真长!实际上,在现实生活中我并不是非常热衷于子查询,所以我的查询往往是这样的: 

select order.id, sum(price.amount), count(item)
from Order as order
    join order.lineItems as item
    join item.product as product,
    Catalog as catalog
    join catalog.prices as price
where order.paid = false
    and order.customer = :customer
    and price.product = product
    and catalog = :currentCatalog
group by order
having sum(price.amount) > :minAmount
order by sum(price.amount) desc
下面的查询统计付款记录处于每种状态中的数量,要排除所有处于AWAITING_APPROVAL状态的,或者最近一次状态更改是由当前用户做出的。它翻译成SQL查询后,在PAYMENT,PAYMENT_STATUS和PAYMENT_STATUS_CHANGE表之间包含两个内部连接和一个用于关联的子查询。 

select count(payment), status.name 
from Payment as payment 
    join payment.currentStatus as status
    join payment.statusChanges as statusChange
where payment.status.name <> PaymentStatus.AWAITING_APPROVAL
    or (
        statusChange.timeStamp = ( 
            select max(change.timeStamp) 
            from PaymentStatusChange change 
            where change.payment = payment
        )
        and statusChange.user <> :currentUser
    )
group by status.name, status.sortOrder
order by status.sortOrder
假若我已经把statusChange集合映射为一个列表而不是一个集合的话,查询写起来会简单很多。 

select count(payment), status.name 
from Payment as payment
    join payment.currentStatus as status
where payment.status.name <> PaymentStatus.AWAITING_APPROVAL
    or payment.statusChanges[ maxIndex(payment.statusChanges) ].user <> :currentUser
group by status.name, status.sortOrder
order by status.sortOrder
下面的查询使用了MS SQL Server的isNull()函数,返回当前用户所属的组织所有账户和未付支出。翻译为SQL查询后,在ACCOUNT, PAYMENT, PAYMENT_STATUS,ACCOUNT_TYPE, ORGANIZATION 和 ORG_USER表之间有三个内部连接,一个外部连接和一个子查询。 

select account, payment
from Account as account
    left outer join account.payments as payment
where :currentUser in elements(account.holder.users)
    and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)
order by account.type.sortOrder, account.accountNumber, payment.dueDate
对某些数据库而言,我们可能不能依赖(关联的)子查询。 

select account, payment
from Account as account
    join account.holder.users as user
    left outer join account.payments as payment
where :currentUser = user
    and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)
order by account.type.sortOrder, account.accountNumber, payment.dueDate
10.13. 提示和技巧(Tips & Tricks)
你不返回结果集也可以查询结果集的大小: 

( (Integer) session.iterate("select count(*) from ....").next() ).intValue()
要依据一个集合的大小对结果集排序,可以用下面的查询来对付一对多或多对多的关联: 

select usr
from User as usr 
    left join usr.messages as msg
group by usr
order by count(msg)
如果你的数据库支持子查询,你可以在查询的where子句中对选择的大小进行条件限制: 

from User usr where size(usr.messages) >= 1
如果你的数据库不支持子查询,可以使用下列查询: 

select usr.id, usr.name
from User usr.name
    join usr.messages msg
group by usr.id, usr.name
having count(msg) >= 1
因为使用了inner join,这个解决方法不能返回没有message的User.下面的方式就可以: 

select usr
from User as usr
    left join usr.messages as msg
group by usr
having count(msg) = 0
JavaBean的属性可以直接作为命名的查询参数: 

Query q = s.createQuery("from foo in class Foo where foo.name=:name and foo.size=:size");
q.setProperties(fooBean); // fooBean has getName() and getSize()
List foos = q.list();
在Query接口中使用过滤器(filter),可以对集合分页: 

Query q = s.createFilter( collection, "" ); // the trivial filter
q.setMaxResults(PAGE_SIZE);
q.setFirstResult(PAGE_SIZE * pageNumber);
List page = q.list();
集合元素可以使用查询过滤器(query filter)进行排序或者分组: 

List orderedCollection = s.filter( collection, "order by this.amount" );
List counts = s.filter( collection, "select this.type, count(this) group by this.type" );
不用初始化集合就可以得到其大小: 

( (Integer) session.iterate("select count(*) from ....").next() ).intValue();

--------------------------------------------------------------------------------
Prev  Up  Next 
Chapter 9. 父子关系(Parent Child Relationships)  Home  Chapter 11. 实例(A Worked Example) 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -