使用hibernate更新和删除时不能使用关系联接操作

来源:互联网 发布:淘宝卖高仿鞋的店铺 编辑:程序博客网 时间:2024/05/17 10:07

本文转载自:i flym
原文地址:http://www.iflym.com/index.php/code/201205140001.html

在使用hibernate进行更新时,经常会碰到以下的操作。如将name为xxx的a下的bList的code信息更新为code+'f'。在使用hibernate时,经常会写下以下的hibernate操作:
update b set b.code='f'+ b.code where b.a.name='xxx'
然而,这句看似没有错误的hql语句,在hibernate进行运行时,却会产生一个奇怪的现象。在生成的hql中,会在表b后面出现一下奇怪的逗号,会报一个错误的sql解析错误的异常,并且在生成的hql中,所没有出现在链接时所使用的a。

原因在于hibernate在进行更新以及删除时候时,并不支持联接操作,包括含有隐式的联接也是不行的。在相应的hibernate jira界面,可以看到以问题的错误:https://hibernate.onjira.com/browse/HHH-2408。
在官方的hibernate手册时,有一条很不起眼的描述。http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/batch.html#batch-direct。
描述如下:
DML-style operations
Some points to note:
No joins, either implicit or explicit, can be specified in a bulk HQL query. Sub-queries can be used in the where-clause, where the subqueries themselves may contain joins.
即不允许联接,不管在主体中还是Where中。不过可以使用子查询来重新进行这种操作,在子查询中可以使用子查询。所以,我们的hql将写成以下这种形式:
update b set b.code='f'+b.code where exists(select1 from b as x where x = b and x.a.name='xx')
我们暂不论此hql是否效率更高或者更好,单就语法来讲,这个hql是正确的。然而,在生成的sql中,即会报一个错误,即列不是惟一的错误。其错误描述在mysql中为:SQL Error: 1052, SQLState: 23000,Column xxx in where clause is ambiguous;而在oracle中为ORA-00918 for ambiguous column。其问题在于,在生成的exists子句中,其中的x=b,直接被hibernate翻译成为了id = id,在这种情况下hibernate直接忽略了子查询中的别名,从而造成了这种错误。
对于这种错误,hibernate也有一个对应的问题描述,即HHH-5785:HQL UPDATE omits alias when referencing an entity。详细的描述界面为:https://hibernate.onjira.com/browse/HHH-5785。

最终的写法修改为
update b set b.code='f'+b.code where exists(select1 from b as x where x.id = b.id and x.a.name='xx')
(备注:以上代码在mysql下可能会出现报更新表不能在查询表的错误,暂时忽略,仅从语法层面分析)。

最终问题解决,牵扯到了hibernate已知的两个问题,一是不能在批量更新(包括删除)中使用联接(隐式和显式),二是在子查询中必须使用类似a.id=b.id这种显示的属性比较,而不能直接使用对象比较,避免hibernate直接忽略掉相应的别名。

本文转载自:i flym

原文地址:http://www.iflym.com/index.php/code/201205140001.html


原创粉丝点击