假设我有一个grails域类,看起来像
class Person {
Address address
}
我也可以宣布它为
class Person {
static hasOne = [address:Address]
}
第二种方法是将外键移动到Address表,而不是person表。
这样做的实际好处(或缺点)是什么?据我所知,他们都会使用外键,只是外键住在哪里的问题。
如果地址表上存在外键,则该地址只能有一个人。如果外键在人员表上,则多个人员可以具有相同的地址。
这不是关于哪种方式更好/更糟。这是关于对数据建模的正确方法。
我发现在Grails中使用hasOne
特别令人困惑。例如,这个问题询问当toOne关系声明如下时会发生什么:
class Person {
static hasOne = [address: Address]
}
如上所述,这会导致person_id
外键出现在Address表中,这意味着每个Address只能指向一个人。我觉得奇怪的是,即使代码写为"一个人有一个地址",实际结果却是"一个地址有一个人"。
事实上,如上所述,没有任何东西(在数据库级别)阻止多个地址记录指向同一个人,这意味着一个人根本不必有一个地址。
有趣的是,如果你创建这样的Address类,你会得到相同的数据库表示:
class Address {
Person person
}
person_id
外键将在Address表中,就像前面的例子一样,但很明显,如果不以某种方式定义关系,就无法从代码中的Person到Address。
同样有趣的是,如果您在数据库中建模从Person到Address的toMany关系,您将使用相同的表布局。您可以将父表的主键(person_id)放入子表中。从数据库的角度来看,使用hasOne
可以创建与toMany关系相同的结构。
当然,我们不仅仅是在创建数据库表,我们还在创建Grails域类,这些类具有一些与之相关的行为,以及一些关系语义的强制执行。在这个特定的业务示例中,您可能不想与多个人共享同一个地址记录,只想单独存储地址(可能是为一个人有多个地址的那一天做准备)。我可能会投票支持这种方法:
class Person {
Address address
static constraints = {
address unique:true
}
}
address_id
外键将在Person表中,并且唯一约束将强制没有两个Person记录指向同一地址。
我建议如下。。。
class Person {
...
static hasOne = [address: Address]
}
class Address {
...
static belongsTo = [person: Person]
}
一个人有一个地址,这个地址属于一个人。
这样,当你删除一个人时,地址也会被删除,不会有任何问题。
我认为这是更好的方法。
人员">hasOne">地址和联系人。
在"子"表上设置外键更有意义,因为这样,如果缺少父表,子表就会断开。个人可以在没有地址的情况下存在,但没有个人的"个人地址"是没有意义的。因此地址应该是关系中较弱的一方。
在grails中这样做,两个实体都会有彼此的引用,所以不会觉得奇怪。此外,当您保存人员时,默认级联行为将保存并删除地址,但如果您想删除Address则Person将保持保存状态。