grails hasOne vs direct成员变量

Jef*_*rey 19 grails foreign-keys grails-orm has-one

假设我有一个grails域类,看起来像

class Person {
    Address address
}
Run Code Online (Sandbox Code Playgroud)

我也可以声明它

class Person {
  static hasOne = [address:Address]
}
Run Code Online (Sandbox Code Playgroud)

第二种方法是将外键移动到Address表而不是person表.

这种方式与另一种方式有什么实际的好处(或缺点)?据我所知,他们都会使用外键,这只是外键所在的问题.

Jam*_*eeh 27

如果外键存在于地址表中,则该地址只能有一个人.如果外键在人员表上,则多个人可以具有相同的地址.

这不是关于哪种方式更好/更糟.这是关于建模数据的正确方法.


Cra*_*ley 22

我发现hasOne在Grails中的使用特别令人困惑.例如,这个问题询问当toOne关系声明如下时会发生什么:

class Person {
  static hasOne = [address: Address]
}
Run Code Online (Sandbox Code Playgroud)

如上所述,这会导致person_id外键出现在Address表中,这意味着每个Address只能指向一个Person.然而,我发现奇怪的是,即使代码被写成"一个人有一个地址",实际结果是"一个地址有一个人".

实际上,如上所述,没有任何东西(在数据库级别)阻止多个地址记录指向同一个Person,这意味着一个Person实际上并不一定要有一个地址.

有趣的是,如果您创建了这样的Address类,您将获得相同的数据库表示:

class Address {
    Person person
}
Run Code Online (Sandbox Code Playgroud)

person_id外键会在地址表中,就如同像在前面的例子,但显然,你不能从人到代码的地址没有定义在某种程度上这种关系也得到.

同样有趣的是,如果你在数据库中从Person到Address建模toMany关系,你将使用相同的表格布局.您将父级的主键(person_id)放入子表中.从数据库的角度来看,使用hasOne创建与toMany关系将创建的结构相同的结构.

当然,我们不只是创建数据库表,我们创建的Grails域类具有与之相关的一些行为,以及一些关系语义的实现.在这个特定的业务示例中,您可能不希望与多个人共享相同的地址记录,您只想单独存储地址(可能准备人员有多个地址的那一天).我可能会投票支持这种方法:

class Person {
    Address address

    static constraints = {
        address unique:true
    }
}
Run Code Online (Sandbox Code Playgroud)

address_id外键将在Person表,以及独特的约束将强制执行,没有两个人记录在同一个地址指向.

  • 非常有趣,感谢您的想法! (2认同)

小智 9

我建议以下......

class Person {
  ...
  static hasOne = [address: Address]
}

class Address {
    ...
    static belongsTo = [person: Person]
}
Run Code Online (Sandbox Code Playgroud)

一个人有一个地址,地址属于一个人.

通过这种方式,当您删除一个人时,该地址也将被删除,没有问题.

我认为这是更好的方法.

  • 尽管您死后通常不会删除房屋:D (2认同)

小智 7

" hasOne " 地址地址 " 属于关联 "的.

将外键放在"子"表上更有意义,因为如果父项丢失,子项将会中断.一个可以在没有地址的情况下存在,但没有人的"人的地址"是没有意义的.所以地址应该是关系中较弱的一面.

这样在grails中这两个实体都会相互引用,所以不会觉得奇怪.此外,默认级联行为将在您保存Person时保存和删除地址,但如果要删除地址,Person将保持保存状态.