You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 05:25:27