论坛首页 Java企业应用论坛

为什么双向关联的配置老是用Set 而不用 List?

浏览 21794 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2007-04-13  
用set除了方便之外

也就是set本身的特征(无重复元素)优点了
0 请登录后投票
   发表时间:2007-04-14  
开发过程中List对象肯定要远远多于Set对象,如果仅仅是为了不重复,那是不是有点因小失大了?
0 请登录后投票
   发表时间:2007-04-14  
hanfengmvp 写道
开发过程中List对象肯定要远远多于Set对象,如果仅仅是为了不重复,那是不是有点因小失大了?

用set 有什么损失? 难道需要很多地方去把set转成list?
0 请登录后投票
   发表时间:2007-04-14  
除了上述各位说的原因外,我再补充一点。
因为1对多的关联,从逻辑上讲是无序的。
我们都知道Set是一个集合,里面的集合是无序的,而list不光光是个容器(虽然大家都把它当容器用)它是个列表,强调元素与元素的先后关系。请问我们数据库里得数据行有先后顺序吗?显然没有。元素的先后顺序是由业务逻辑决定的,比如按照出生年月排序,按照年龄排序。所以抓取出来得多个对象可以有多种排序方式。所以我们通过hibernate抓取出来的对象应该是个Set,然后更具不同的逻辑进行排序。
1 请登录后投票
   发表时间:2007-04-14  
对于一对多关联当中的List,需要在数据库里面维护一个index列,如果List当中的某个元素被删除,那么Hibernate会连续发送多条update语句,更新后续所有元素的index列,以确保index的连续性(在inverse为false的情况下),如果你选择自己维护index列,也同样会面临这个问题,甚至更棘手(在inverse为true的情况下),所以List被谨慎的使用在极其罕见的场合。

一般来说,我会选择在1对关联当中使用Bag,在多对多关联当中使用Set。
0 请登录后投票
   发表时间:2007-04-15  
因为一般关联是确实是没有重复的记录,所以就是通常工具从数据库表生成映射文件就用了set,可是有时显示集合中的数据是有要保持顺序的需求,这个时候就要选用list(用bag映射的那种,用list映射的那种是需要数据库中存有索引字段,还要连续的)

list要比set效率高,因为set是把元素存在map的key所在位置上,况且list比set使用起来也要方便,list可直接用索引取值,set这一般通过iterator遍历。
0 请登录后投票
   发表时间:2007-04-15  
首先应该是看是怎样的需求。如果要求没有重复,固然是用set;如果是要求保持插入数据库的先后顺序,就用list。
set需要注意equals和hashcode实现,但是list还要担心robbin说的问题,所以相比之下确实set用起来更加简单了。
至于效率的话,单看遍历的效率当然是list更高,但是hibernate要维护index列,相信多次update带来的性能牺牲肯定是比遍历要大了。
0 请登录后投票
   发表时间:2007-04-15  
不要误会了robbin所说的话,他所说的要特别慎用list是指的hibernate映射文件中的list类型,而不是实体类中的List类型。映射文件中用Bag类型,在实体类中是可以对应List的。

至于说排序,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类型。
0 请登录后投票
   发表时间:2007-04-16  
嗯,这么说采用Bag(java.util.List)或者Set(java.util.Set)都是可以的啊
顺便问一下:领域对象需要重写.equals和.hashCode()么?如果需要的话应该用到id字段么?
0 请登录后投票
   发表时间:2007-04-17  
说到关联使用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时倒是没有问题。

好像我是在这里极力推荐使用List,其实也不是,各人有各人的习惯。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics