I'm trying to create a bi-directional relationship between two domains in Grails (parent-child) but i can't seem to make it work. According to Grails GORM documentation oneToMany I should be able to create a hasMany(Parent) and a belongsTo(Child) between a parent and a child to create a bi-directional relationship but it just doesn't work for me.
I have the following two domains:
class Game {
String name
String description
Double price
}
class Review {
static belongsTo = [game: Game]
String reviewText
Date reviewDate
}
then i create a grails dbm-gorm-diff file.groovy
i get a file with the following
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")
}
}
at this point everything is 'perfect' so to say so i run grials dbm-update
so the changes get transferred to the DB, but then i want to make this relationship bi-directional therefore i update my Game domain with the 'hasMany' as follows
class Game {
static hasMany = [reviews: Review]
String name
String description
Double price
}
after making the changes to the Game domain i proceed to run grails dbm-gorm-diff fileupdated.groovy
so i can finally create the bi-directional relationship but i get an empty migration file
databaseChangeLog = {
}
Note: even if put the 'hasMany" in the first migration on the Game domain I receive the same results, a relationship child-parent(reviews to game) is created, but the parent-child(game to reviews) doesn't get created. On the tutorial i was trying to follow it does work. I'm using grails 2.4.4.
Why is the oneToMany relationship not being created?
thank you,
efx
Edit:
-I create a Game example like below and receive 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
-Then i proceed to create 2 reviews for that game and receive review id 2 and 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
-now if everything was done correctly with my bidirectional domains i should be able to query all my reviews from game but i get a null
groovy:000> retrieve = com.pluralsight.Game.get(1)
===> com.pluralsight.Game : 1
groovy:000> retrieve.reviews
===> null
therefore i'm not sure why my oneToMany from Game to Review is not working
g.addToReviews(new Review(review:date new Date(), reviewText: 'Review 1')
. Then when you save the game the review will be saved as well:g.save()
– Emmanuel Rosagroovy:000> retrieve.addToReviews(new Review(reviewDate: new Date(), reviewText: 'Review 3')) ERROR org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed: groovysh_evaluate: 2: unable to resolve class Review @ line 2, column 23. retrieve.addToReviews(new Review(reviewDate: new Date(), reviewText: 'Review 3'))
– efxg.addToReviews(new com.pluralsight.Review(review:date new Date(), reviewText: 'Review 1')
– Emmanuel Rosagroovy:000> retrieve.addToReviews(new com.pluralsight.Review(reviewDate: new Date(), reviewText: 'Review 3')) ERROR groovy.lang.MissingMethodException: No signature of method: com.pluralsight.Game.addToReviews() is applicable for argument types: (com.pluralsight.Review) values: [com.pluralsight.Review : (unsaved)] Possible solutions: getReviews()
i don't think is ever going to work if there's no relationship from Game to Review. Right now the only relationship is from Review to Game but no vice versa – efxGame
toReview
. Use either one of the examples in my answer. The many is added to the one regardless of whether the association is uni-directional or bi-directional. BTW, feel free to sign up for my Grails Noob Slack community (at emmanuelrosa.com). The StackOverflow chat is going to kick in soon, and it sucks. – Emmanuel Rosa