为什么建议避免外键上的单向一对多关联?

时间:2010-01-19 10:03:29

标签: java sql hibernate rdbms

  

可能重复:
  Hibernate unidirectional one to many association - why is a join table better?

在Hibernate在线文档中,在7.2.3一对多部分中,提到了:

  

单向一对多关联   在外键上是一个不寻常的案例,   并不推荐。你应该   而是使用这种连接表   协会。

我想知道为什么?我唯一想到的是,它可以在级联删除期间产生问题。例如,Person指的是外键上一对多关系的地址,该地址将拒绝在该人之前删除。

任何人都可以解释推荐背后的理性吗?

以下是参考文档内容的链接:7.2.3. One-to-many

我已复制粘贴实际内容:

  

外键上的单向一对多关联是   不寻常的情况,不推荐。

<class name="Person">
    <id name="id" column="personId">
        <generator class="native"/>
    </id>
    <set name="addresses">
        <key column="personId" 
            not-null="true"/>
        <one-to-many class="Address"/>
    </set>
</class>

<class name="Address">
    <id name="id" column="addressId">
        <generator class="native"/>
    </id>
</class>
     
create table Person (personId bigint not null primary key)
create table Address (addressId bigint not null primary key, personId bigint not null)
     

您应该使用连接表进行此类关联。

1 个答案:

答案 0 :(得分:14)

  

单向一对多关联   在外键上是一个不寻常的案例,   并且不推荐。

这有两个方面:

  • 单向
  • 一个对多

thread @CalmStorm 删除的答案仅链接到地址中的第二个,但让我们从它开始。

该线程建议用连接表替换一对多关系,因为否则一对多方法'使用不属于该实体的列填充多个边表,仅用于“链接”porpuses (原文如此)”。这种策略可能会在Hibernate层中产生一个干净的模型,但不幸的是它会导致数据库损坏。

因为SQL只能声明子记录有父记录;没有办法强制执行父母必须有孩子的规则。因此,没有办法坚持表中的连接表中有条目,结果是有可能有孤立的子记录,这是外键要防止的。

我还有其他几个异议,但下一个最重要的是不恰当。交叉表旨在表示多对多关系。使用它们来表示一对多关系会让人感到困惑,并且需要太多额外的数据库对象。

所以,第二个方面:单向一对多关联。这些问题是Hibernate默认处理它们的特殊方式。如果我们在同一个事务中插入父项和子项,Hibernate会插入子记录,然后插入父项,然后使用父项的键更新子项。这需要可延迟的外键约束(哎呀!),也可能是可延迟的非空约束(双重约束)。

这有几种解决方法。一种是使用双向一对多关联。根据{{​​3}},这是最常见的方法。另一种方法是调整子对象的映射,但这有其自身的分支。