与Grails hasMany创建双向关系,且belongsTo不起作用

时间:2016-02-21 05:58:11

标签: grails gorm

我正在尝试在Grails(父子)中创建两个域之间的双向关系,但我似乎无法使其工作。 根据{{​​3}},我应该能够在父项和子项之间创建一个hasMany(Parent)和一个belongsTo(Child)来创建双向关系,但它对我来说不起作用。

我有以下两个域:

class Game {
   String name
   String description
   Double price
}

class Review {
   static belongsTo = [game: Game]
   String reviewText
   Date reviewDate

}

然后我创建一个grails dbm-gorm-diff file.groovy我得到一个包含以下内容的文件

databaseChangeLog = {

 changeSet(author: "efx (generated)", id: "1456032538941-1") {
    createTable(tableName: "game") {
        column(name: "id", type: "int8") {
            constraints(nullable: "false", primaryKey: "true", primaryKeyName: "gamePK")
        }

        column(name: "version", type: "int8") {
            constraints(nullable: "false")
        }

        column(name: "description", type: "varchar(255)") {
            constraints(nullable: "false")
        }

        column(name: "name", type: "varchar(255)") {
            constraints(nullable: "false")
        }

        column(name: "price", type: "float8") {
            constraints(nullable: "false")
        }

        column(name: "reviews_id", type: "int8") {
            constraints(nullable: "false")
        }
    }
}

 changeSet(author: "efx (generated)", id: "1456032538941-2") {
    createTable(tableName: "review") {
        column(name: "id", type: "int8") {
            constraints(nullable: "false", primaryKey: "true", primaryKeyName: "reviewPK")
        }

        column(name: "version", type: "int8") {
            constraints(nullable: "false")
        }

        column(name: "review_date", type: "timestamp") {
            constraints(nullable: "false")
        }

        column(name: "review_text", type: "varchar(255)") {
            constraints(nullable: "false")
        }
    }
}

 changeSet(author: "efx (generated)", id: "1456032538941-4") {
    createSequence(sequenceName: "hibernate_sequence")
}

changeSet(author: "efx (generated)", id: "1456032538941-3") {
    addForeignKeyConstraint(baseColumnNames: "reviews_id", baseTableName: "game", constraintName: "FK_jnjkmccicsjmsvqub534xcnnm", deferrable: "false", initiallyDeferred: "false", referencedColumnNames: "id", referencedTableName: "review", referencesUniqueColumn: "false")
}

}

此时所有内容都是“完美的”,所以说我运行grials dbm-update所以更改会转移到数据库,但后来我想让这种关系双向,因此我更新了我的游戏域名'hasMany'如下

class Game {
   static hasMany = [reviews: Review]
   String name
   String description
   Double price
}

在对游戏域进行更改后,我继续运行grails dbm-gorm-diff fileupdated.groovy,这样我最终可以创建双向关系,但我得到一个空的迁移文件

databaseChangeLog = {
}

注意:即使在游戏域的第一次迁移中放入'hasMany',我也会收到相同的结果,会创建一个关系子父(游戏评论),但父母 - 孩子(评论游戏)没有被创建。在教程中我试图遵循它确实有用。我正在使用grails 2.4.4。

为什么没有创建oneToMany关系?

谢谢,

EFX

修改

- 我创建一个像下面这样的游戏示例并收到id = 1

    groovy:000> g = new com.pluralsight.Game([description: 'Game Desc', name: 'The Game', price: '1.99'])
===> com.pluralsight.Game : (unsaved)
groovy:000> g.save()
===> com.pluralsight.Game : 1

- 然后我继续为该游戏创建2条评论,并收到评论ID 2和3

    groovy:000> r = new com.pluralsight.Review([game: g, reviewDate: new Date(), reviewText: 'Review 1'])
===> com.pluralsight.Review : (unsaved)
groovy:000> r.save()
===> com.pluralsight.Review : 2

groovy:000> r2 = new com.pluralsight.Review([game: g, reviewDate: new Date(), reviewText: 'Review 2'])
===> com.pluralsight.Review : (unsaved)
groovy:000> r2.save()
===> com.pluralsight.Review : 3

- 如果所有内容都使用我的双向域正确完成,我应该能够从游戏中查询我的所有评论,但我得到一个空

    groovy:000> retrieve = com.pluralsight.Game.get(1)
===> com.pluralsight.Game : 1
groovy:000> retrieve.reviews
===> null
因此,我不确定为什么我从游戏到评论的oneToMany无效

3 个答案:

答案 0 :(得分:0)

为什么期望数据库发生变化?

重要的是要了解Grails / GORM(和Hibernate)在谈论双向关系时的意思。

当两端关系都引用另一方时,关系称为双向。因此,Game的集合为Reviews,而Review则引用Game。这只是谈论应用程序代码。数据库只需要1个外键即可完全存储关系。

您也可以使用连接表,但在这种情况下(在我看来)这实在是太过分了。但Grails / GORM允许它,只需在文档中查看如何在static mapping部分中映射它。

答案 1 :(得分:0)

如您所知,有两种形式的一对多关联:单向和双向。两者都需要static hasMany = ...。只有在使用static belongsTo = ...的双向一对多关联的情况下才会这样做:

单向

class Game {
   String name
   String description
   Double price

   static hasMany = [reviews: Review]
}

class Review {
   String reviewText
   Date reviewDate    
}

双向

class Game {
   String name
   String description
   Double price

   static hasMany = [reviews: Review]
}

class Review {
   String reviewText
   Date reviewDate

   static belongsTo = [game: Game]
}

数据库实施

对于单向一对多的情况,您最终会得到三个表:gamereviewgame_reviewgame_review通过使用两列来加入其他两个表:游戏ID和审阅ID。 gamereview表格保持孤立;他们只有{em>到 game_review表格的关系。

在双向一对多中,您将获得两个表:gamereview。但是,review表将包含一个外键列:游戏ID。没有连接表保持gamereview表彼此独立。

我希望有所帮助。您可以在我的articles之一了解有关此内容的更多信息。

答案 2 :(得分:0)

我要感谢@hansboogards和@emmanuelrosa的时间,我发现了一篇非常有趣的关于hibernate的文章及其导致的头痛GORM Gotchas,并找到了我无法从Game域调用的原因回顾这是因为hibernate并没有将它们放在数据库中,尽管我已经完成了保存。

  

即使在save()(没有显式刷新)之后,这也会打印空值。只有当您刷新会话时,子域实例才会设置其ID。这与我们之前看到的多对一案例完全不同,在这种情况下,您不需要将Location实例的显式刷新持久保存到数据库!重要的是要意识到差异存在,否则你将陷入困境。