通过hql控制hibernate一对多的集合属性的排序

5 篇文章 0 订阅
1 篇文章 0 订阅

【问题】

  • 当hibernate实体中存在一对多关系集合时(比如:Person 1->* Addr ) ,无法完全使用hql来控制集合属性内部的排序。
  • 假设我们想addrs集合按照addr.id排序,理所当然的想到硬编码@OrderBy("id"),可是这样的话无论hql中是否已经有orderby语句,最后都会追加一句orderby addrs.id,这样在一些我们不想将addrs按照id排序的场景下就会有问题(hibernate并不会检测你是否在hql定制了排序,始终默认添加),这不是我们想要的
  • 但是如果不加@OrderBy("id"),那么产生的集合底层是hashset(不要问我怎么知道的都是泪= =。 调试了好久,其实一开始就应该想到)

 【具体解决问题的过程】

  • 首先想确定到底是不是hibernate底层返回的顺序就是不对的(因为当时没去看返回的PersistCollection的私有变量 = =,如果看了的话,就可以跳过下面的很大一部分解析过程)。看query,一路追查到 org.hibernate.loader.Loader.readCollectionElement,发现有日志可以打(log4j.logger.org.hibernate.loader=DEBUG),开启后可以清楚看到hibernate读取每一行的过程,同时也得到结论,读取的时候顺序是按照我hql的排序规则,没问题。
  • 在以上调试过程中发现org.hibernate.mapping.Set.getDefaultCollectionType 方法 
    public class Set extends Collection {
    
    public CollectionType getDefaultCollectionType() {
    		if ( isSorted() ) {
    			return TypeFactory.sortedSet( getRole(), getReferencedPropertyName(), isEmbedded(), getComparator() );
    		}
    		else if ( hasOrder() ) {
    			return TypeFactory.orderedSet( getRole(), getReferencedPropertyName(), isEmbedded() );
    		}
    		else {
    			return TypeFactory.set( getRole(), getReferencedPropertyName(), isEmbedded() );
    		}
    	}
    
    //...以下是集成父类Collection中的方法
    public boolean hasOrder() {
    		return orderBy!=null || manyToManyOrderBy!=null;
    	}
    }
     好像瞬间明白了些什么。。没错,就是直接写@orderby注解就是linkedhashset了,这样就能保证数集合类根据hql的规则,也就是实际返回数据的顺序来进行排序。。唉好坑~最终解决方法实在是太简单了,绕了一大圈。 

【结论以及解决方法】

  • @Entity
    @Table(name = "...")
    public class Person{
    
    @OneToMany(mappedBy = "person")
    @OrderBy //***没错就是这行,只写注解,不写参数!!!***
    public Set<Addr> getAddrs() {
    return addrs;
    }
    
    }
      

 PS: 大家可能要问这样排序好像不对吧!没错,我省略了主表的排序语句,这个大家记得自己补上吧,举例就是 select p from Persion p left join fetch p.addrs a order by p.id,a.id  就是这样,不要忘了主表的排序哟。

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值