I am starting to use grails and I have stumble into a behaviour that I don't understand.
Given this domain class
class Team {
String name
Date since
Date until
static hasMany = [teamMembers:Player]
static constraints = {
name nullable: false, blank: false, unique: true
until nullable: true
until(validator: { val, obj ->
val?.after(obj.since)
})
teamMembers maxSize: 8
//teamMembers size: 0..8
}
}
I wanted to have an integration test that checks that you can't actually have more than 8 players in one team so I wrote a simplified version of this:
void "The team can only have up to 8 players"(){
given:
Player[] players = (1..9).collect {new Player(name: "Foo")}
Team t = new Team(name:"Bar", since: new Date())
expect:
players.each {it.validate()}
t.validate()
when:
players.each {it.save()}
t.save()
players.each {t.addToTeamMembers(it)}
then:
t.validate() == false
t.getTeamMembers().size() == 9
Team.get(t.id).teamMembers.size == 9
Team.first().teamMembers.size == 9
Team.findAll()[0].teamMembers.size == 9
Team.findByName("Bar").teamMembers.size == 9
}
As far as I know, get, find *, etc hit the database. So why does my team fail to validate (expected behaviour) but it has 9 players in the database? What am I missing?
Notes: Name is not PK for players and I have tested with both constraints, size and maxSize.
Related to this problem, I have found this answer from Peter Ledbrook:
As a summary for this link:
... as soon as you call "save()" on the Team object, it is attached to the session. Any subsequent changes to that object will then be persisted to the database including any player you add
If that is right (I haven't really tried), that should fix it:
void "The team can only have up to 8 players"(){
given:
Player[] players = (1..9).collect {new Player(name: "Foo")}
Team t = new Team(name:"Bar", since: new Date())
expect:
players.each {it.validate()}
t.validate()
when:
players.each {t.addToTeamMembers(it)}
t.save()
then:
!t.validate()
}
which means that should only save once the team object (supposing Player has a belongsTo to the Team domain class). Let me know if that works.