http://www.114java.com/javakaiyuankuangjia/hibernate/201001/853.html
在双向关联的hibernate在一对多配置的时候默认总是给我们提供set类型,最近在做电力系统后台用户角色的时候就遇到了这个问题。
因为你获得的set是一个无序的集合,因此,在现实页面上的时候可能每次都会改变,在hibernate的配置文档中
<set name="roles" table="USER_ROLE" cascade="save-update" inverse="true" outer-join ="false" lazy="false" order-by="ROLEID" >
<key column="USERID" />
<many-to-many class="com.fjnetpower.zzjf.business.model.entities.Role" column="ROLEID" />
</set>
加上order-by这个属性即可解决问题
关于这个问题的深入研究:
1、其实hibernate是有提供list映射的, list就是bag类型,bag适合关联的集合类中有排序需求
在配置list的时候,也有几种方法:指定list-index,这也就要在数据库中对应创建一个字段表示顺序
对于一对多关联当中的List,需要在数据库里面维护一个index列,如果List当中的某个元素被删除,那么Hibernate会
连续发送多条update语句,更新后续所有元素的index列,以确保index的连续性(在inverse为false的情况下),如果
你选择自己维护index列,也同样会面临这个问题,甚至更棘手(在inverse为true的情况下),所以List被谨慎的使用在
极其罕见的场合。
但是,这里所说的要特别慎用list是指的hibernate映射文件中的list类型,而不是实体类中的List类型。映射文件中
用Bag类型,在实体类中是可以对应List的。
2、至于说排序,List(Bag映射)和Set都是可以排序的,hibernate有自己的Set、List、Map实现,其内部根据使
用的排序方式使用Java.util中的各种不排序的或排序的集合实现类。
Set映射有两种排序方式,一是使用映射文件中的sort属性,一般需要自己实现一个java.util.Comparator,sort属性
指定自己实现的比较类,hibernate返回给客户的实际是Set的TreeSet实现,将该比较类作为treeSet的比较器,这种
排序是在内存中进行的,可以在比较器中按实体类的某个字段排序或实现更复杂的排序方法,非常灵活,但是要自己实
现比较器,麻烦一些。
另一种方法是使用映射中的order-by属性,可以指定表中的一个排序字段,排序是在数据库中进行的,hibernate返回
是LinkedHashSet实现,可以保持对象的前后次序。
所以参考中说在实体类中定义子集合时不要定义成HashSet,而应该是Set接口,因为它返回的不一定是HashSet。
对于List(Bag映射),可以指定order-by排序字段,并不需要index列。
个人感觉List使用起来方便一些,所以一般在实体类中定义List,对应映射中的Bag类型。
3、说到关联使用Set可以避免重复对象可能也只是自我感觉可靠一些,实际上不会有重复对象出现,每个关联对象都有
自己的主键id,获取集合时只是简单的外键关联查询,没有复杂的查询,哪来的重复对象呢。如果集合里不是自己定义
的pojo而是String、Integer等简单类型倒是可能会重复,不过那是特殊的应用了。对于hql等查询才需要考虑可能出现
的重复对象问题(同一对象的重复引用),但是hibernate并没有提供返回Set的查询方法,用query.iterate()也会有重复对象。
因为相同id的对象在session中只会保存一份,所以如果始终在同一session中那么不实现equals和hashCode方法也
可以放心的使用集合的contains等方法,不管是用hql查询还是load、get方法,对于同一id返回的都是同一个对象,即
使对于因延迟加载而代理的对象也是始终返回该代理对象,忽然想到对于get方法如果某id前面有过代理对象,虽然一定会加
载实体对象数据,但返回的还是该代理对象,以前一直觉得很奇怪,可能就是基于这样的考虑。看来OpenSessionInView方
法很有好处啊。
如果要实现equals和hashCode方法,当然首先要考虑到id字段,忽然想到光id字段还不够,因为对于新建的对象,id为
null,如果新建两个对象然后放到Set中,会认为两个对象相等,只能放入第一个,保存时也只能保存一个,反而不重写
equals和hashCode时倒是没有问题