我正在尝试在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无效
答案 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]
}
对于单向一对多的情况,您最终会得到三个表:game
,review
和game_review
。 game_review
表通过使用两列来加入其他两个表:游戏ID和审阅ID。 game
和review
表格保持孤立;他们只有{em>到 game_review
表格的关系。
在双向一对多中,您将获得两个表:game
和review
。但是,review
表将包含一个外键列:游戏ID。没有连接表保持game
和review
表彼此独立。
我希望有所帮助。您可以在我的articles之一了解有关此内容的更多信息。
答案 2 :(得分:0)
我要感谢@hansboogards和@emmanuelrosa的时间,我发现了一篇非常有趣的关于hibernate的文章及其导致的头痛GORM Gotchas,并找到了我无法从Game域调用的原因回顾这是因为hibernate并没有将它们放在数据库中,尽管我已经完成了保存。
即使在save()(没有显式刷新)之后,这也会打印空值。只有当您刷新会话时,子域实例才会设置其ID。这与我们之前看到的多对一案例完全不同,在这种情况下,您不需要将Location实例的显式刷新持久保存到数据库!重要的是要意识到差异存在,否则你将陷入困境。