I find the use of hasOne
in Grails to be particularly confusing. For example, this question asks what happens when a toOne relationship is declared as follows:
class Person {
static hasOne = [address: Address]
}
As stated above, this causes the person_id
foreign key to appear in the Address table, which means that each Address can only point at one Person. What I find bizarre, then, is that even though the code is written as "a Person has one Address", the actual result is that "an Address has one Person".
And in fact, defined solely as above, there's nothing (at the database level) preventing more than one Address record from pointing at the same Person, which means that a Person doesn't really have to have one Address after all.
Interestingly, you'd get the same database representation if you created the Address class like this:
class Address {
Person person
}
The person_id
foreign key will be in the Address table, just as like in the previous example, but obviously, you can't get from the Person to the Address in the code without defining that relationship in some way as well.
Also interesting is that, if you were modeling a toMany relationship from Person to Address in the database, you'd use the same table layout. You'd put the parent's primary key (person_id) into the child table. From a database perspective then, using hasOne
creates the same structure that a toMany relationship would create.
Of course, we're not just creating database tables, we're creating Grails domain classes that have some behavior associated with them, and some enforcement of relationship semantics. In this particular business example, you probably don't want to share the same Address record with multiple People, you just want to store the Address separately (maybe preparing for the day when a Person has multiple Addresses). I'd probably vote for this approach:
class Person {
Address address
static constraints = {
address unique:true
}
}
The address_id
foreign key will be in the Person table, and the unique constraint will enforce that no two Person records are pointing at the same Address.