23

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

class Person {
    Address address
}

我也可以将其声明为

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

第二种方法是将外键移动到地址表而不是人员表。

与另一种方式相比,这样做的实际好处(或缺点)是什么?据我了解,它们都将使用外键,这只是外键所在位置的问题。

4

4 回答 4

30

如果地址表上存在外键,则该地址只能有一个人。如果外键在 person 表上,则多个人可以有相同的地址。

这不是关于哪种方式更好/更差。这是关于什么是对数据建模的正确方法。

于 2012-10-15T17:09:04.430 回答
25

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

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

如上所述,这会导致person_id外键出现在 Address 表中,这意味着每个 Address 只能指向一个 Person。那么,我觉得奇怪的是,即使代码写成“一个人有一个地址”,实际结果是“一个地址有一个人”。

事实上,仅按照上面的定义,没有什么(在数据库级别)阻止多个地址记录指向同一个 Person,这意味着一个 Person 并不真的必须有一个 Address。

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

class Address {
    Person person
}

person_id键将在 Address 表中,就像在前面的示例中一样,但显然,如果不以某种方式定义该关系,您就无法从代码中的 Person 到 Address。

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

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

class Person {
    Address address

    static constraints = {
        address unique:true
    }
}

address_id键将在 Person 表中,并且唯一约束将强制没有两条 Person 记录指向同一个地址。

于 2013-04-22T19:34:06.253 回答
9

我建议以下...

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

class Address {
    ...
    static belongsTo = [person: Person]
}

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

这样,当你删除一个人时,地址也会被删除,没有问题。

我认为这是更好的方法。

于 2014-01-31T20:39:56.550 回答
7

hasOne地址地址属于。_

将外键放在“子”表上更有意义,因为这样如果父项丢失,子项就会中断。一个可以没有它的地址而存在,但是没有一个人的“人的地址”是没有意义的。所以地址应该是关系中较弱的一面。

在 grails 中这样做,两个实体都会相互引用,所以不会感觉很奇怪。此外,默认的级联行为将在您保存人员时保存并删除地址,但如果您想删除地址,则人员将保持保存状态。

于 2014-04-14T15:18:12.683 回答