Grails查询Tag域类返回重复实例问题求助
问题根源与解决方案
你遇到的问题核心是复合主键设计不符合唯一性要求。你的Tag域类把wallpaper和location设为复合主键,但数据库里同一组wallpaper_id+wallpaper_location对应多条不同tag的记录——主键必须唯一标识一条记录,这种情况下Hibernate会认为这些记录是同一个实体,所以查询时只会返回第一个实例的多个副本。
方案一:修正复合主键,加入tag字段
把复合主键改成包含wallpaper、location、tag三个字段,确保每条记录都能被唯一标识:
class Tag implements Serializable { Long wallpaper String location, tag static mapping = { if (Environment.current != Environment.TEST) { table name: 'tag', schema: 'jws' // 修改复合主键,加入tag字段 id composite: ['wallpaper', 'location', 'tag'] columns { wallpaper column: 'wallpaper_id', sqlType: 'INTEGER', length: 11 location column: 'wallpaper_location', sqlType: 'VARCHAR', length: 255 tag column: 'tag', sqlType: 'VARCHAR', length: 255 } } version(false) } static constraints = { wallpaper nullable: false, blank: false, maxSize: 11 location nullable: false, blank: false, maxSize: 255 tag nullable: false, blank: false, maxSize: 255 } // 复合主键必须实现equals和hashCode,保证Hibernate能区分不同实例 @Override boolean equals(Object o) { if (this.is(o)) return true if (o == null || getClass() != o.getClass()) return false Tag tag1 = (Tag) o return wallpaper == tag1.wallpaper && Objects.equals(location, tag1.location) && Objects.equals(tag, tag1.tag) } @Override int hashCode() { return Objects.hash(wallpaper, location, tag) } }
方案二:改用独立自增主键(更推荐)
复合主键在ORM场景中容易引发各类问题,更稳妥的方式是给Tag表添加独立自增主键,同时把原有的组合字段设为唯一约束:
class Tag implements Serializable { Long id // 新增独立自增主键 Long wallpaper String location, tag static mapping = { if (Environment.current != Environment.TEST) { table name: 'tag', schema: 'jws' // 配置自增主键,可根据数据库类型调整generator(比如sequence) id column: 'id', generator: 'identity' columns { wallpaper column: 'wallpaper_id', sqlType: 'INTEGER', length: 11 location column: 'wallpaper_location', sqlType: 'VARCHAR', length: 255 tag column: 'tag', sqlType: 'VARCHAR', length: 255 } } version(false) } static constraints = { wallpaper nullable: false, blank: false, maxSize: 11 location nullable: false, blank: false, maxSize: 255 tag nullable: false, blank: false, maxSize: 255 // 添加唯一约束,避免同一wallpaper+location+tag重复 wallpaper unique: ['location', 'tag'] } }
同时需要在数据库中给tag表新增id自增字段,并创建wallpaper_id+wallpaper_location+tag的唯一索引。
为什么你之前的尝试无效?
你试过的重命名tag属性、使用视图、清理项目等操作,都没有触及主键不唯一这个核心问题——Hibernate是通过主键来区分实体实例的,只要主键重复,就会被当作同一个对象处理,所以这些操作都无法改变查询结果重复的现象。
内容的提问来源于stack exchange,提问作者Joshua
相关产品推荐
相关产品推荐

