文档章节

关于为什么单向一对多(one-to-many)要使用关联表的再思考

猪刚烈
 猪刚烈
发布于 2014/10/12 11:40
字数 1034
阅读 17
收藏 0

精选30+云产品,助力企业轻松上云!>>>

 

在传统的数据建模中,允许为 Null 值的外键被认为是一种不好的实践,。这并不是 Hibernate的要求.---Hibernate文档


2013年1月29日:补充:

简单地说,数据库的外键关联描述的最严格与最精准的物关系应该是像“子-父”这样的单向多对一关系,也即,“子”必有“父”!而反方向的一对多的关系并不是其所能准确描述,原因就是“父”未必有“子”,所以从这个角度上说,使用关联表描述单向一对多是更加贴切的。

我在Hibernate2010年的笔记中对为什么单向一对多(one-to-many)的映射要使用关联表做过讨论,但是我觉得那时候的认识并不深刻,也不太具有说服力,今天我有了进一步的思考。

首先必须明确,一对一,一对多或者多对多都是领域对象间的关系,它们体现的是业务层面上各种事物之间的对应关系。这些对应关系与数据库上的外键关联是有本质区别的。但是当我们需要持久化这些数据时,又必须要把它们之间的这些关系以数据库方式保存起来,或者说是以数据库的方式对这些关系进行模拟。很显然,可供我们使用的方式无非就是外键关联和关联表。

我们先来看外键关联:

在所有对象关系中双向一对多也就是最最典型的“父子关系”(注意,严格来说父子关系和双向一对多多对一关系是有一点差别的,那就是父子关系中要求子是一定有父的,而单向多对一中并没有明确要求一方是一定存在的,这个我在后面会再细说)使用外键关联是最贴切的!

外键关联是两张表级别上的关联关系,这里有一个暗含的要求,那就是两张表的全部记录应该都满足这种约束才对(像在父子关系中,子一定有父一样!)。虽然这不是必须的。因为一旦我们允许外键列为空就会使得一些数据可以不受此外键约束,这于我们设置外键关联的初衷就背道而驰了。从一对多的语义上来看,它只期望从单端能够找到一组多端对象,至于多端对象是不是都有一个对应的单端对象,是不再其关心或者表述范围之内的。显然,要实现这种语义,必须置多端对象的外键为可空,来放宽于约束。从数据库设计的角度来看,外键为空是一种不好的设计,而使用关联表则可以避开这个问题。我们可以看到关联表允许我们只是对两表之间的“部分”数据间的关系进行表达。它们这种关系并不是表级别的,也就是说并不是每条记录都有这种关系,这比使用允许外联列为空的外键约束要自然和合理。

由此我想,是不是对于单向多对一(many-to-one)来说,如果它对应的那个one不是必须有的时候,那我们是不是也不应该使用外键关联呢?我想答案是肯定的。

最后再简明的把这个问题描述一下:

因为单向一对多关系中对many方与one方之间的关系没有相关的描述,many方可能有对应的one方也可能没有,在这种情况下使用外键约束是不合适的。而使用关联表的好处就在于可以“规避”这个问题,也就是不正面回应这个问题。因为单向一对多关系本身就不关心这个问题。

猪刚烈

猪刚烈

粉丝 22
博文 708
码字总数 110
作品 1
海淀
程序员
私信 提问
加载中
请先登录后再评论。
NOTE:Hibernate-2010

2009-12-10 为什么“单向一对多”并不推荐使用关联列而使用关联表呢? JPWH一书中的解释是说:如果在“Many"方设外键关联,必须设为可空,而对于数据库设计来说,这增加了数据的“不确定性”...

猪刚烈
2014/10/12
13
0
数据库建立表关系 一对多 多对多 一对一

表之间的关系 外键一对多 多对多 一对一 一对多 确立表与表之间的关系 一定要换位思考(必须两方都考虑周全之后才能得出结论)以员工表和部门表为例先站在员工表看能否有多个员工对应一个部门翻...

osc_3rgq3dae
2019/08/20
2
0
MySQL数据库 外键,级联, 修改表的操作

1.外键: 用来建立两张表之间的关系 - 一对多 - 多对多 - 一对一 研究表与表之间的关系:   1.定义一张 员工部门表     id, name, gender, depname, depdesc   - 将所有数据存放在一张...

osc_4nr2ziai
2019/12/12
3
0
Python 外键 表中字段修改

外键 一 作用: 1.建立表与表之间的关系 2.节省存储空间 3.组织结构清晰 4.提高拓展性 二 如何确定标语表之间的关系 确立表与表之间的关系 一定要换位思考(必须两方都考虑周全之后才能得出结...

osc_3rgq3dae
2019/08/20
3
0
@JoinColumn 详解

原文链接:@JoinColumn详解 原文标的也是转载,但是没有注明原文链接,看起来乱乱的,所以整理一下转载过来,顺便细看一下 1. 一对一 现假设有Person表和Address表,是一对一的关系,在Perso...

DarJeely
04/01
0
0

没有更多内容

加载失败,请刷新页面

加载更多

BuildRun低代码开发教程八节 | 图表和仪表盘展示

课程说明 ▍ 1.1 课程实现功能 本课程为物联网应用平台设计一个仪表盘首页,包括以下内容: 卡片展示设备总数; 卡片展示网关总数; 卡片展示产品总数; 卡片展示产品分组总数; 图表展示各运...

BuildRun团队
28分钟前
11
0
JavaSE第03篇:Java基础语法之运算符和流程控制

本章将会延续JavaSE第02篇,详细讲解Java基础语法中的运算符和流程控制中的顺序结构、分支结构。 第一章:运算符 运算符,简而言之就是运算的符号。 我们通常所理解的运算一般和数学有关系,...

雷哒哒
31分钟前
3
0
jenkins更换清华源

[root@localhost ~]# find / -name "default.json" /var/lib/jenkins/updates/default.json[root@localhost ~]# sed -i 's/http:\/\/updates.jenkins-ci.org\/download/https:\/\/mirro......

MadDragon
43分钟前
25
0
springboot 学习

1、搭建环境 helloworld http://c.biancheng.net/view/5316.html 或者懂了直接上这个网站建: https://start.spring.io/ 2、整合jdbc...

深夜里写着琴弹着代码
50分钟前
16
0
如何检查Android上的互联网访问? InetAddress永远不会超时

问题: I got a AsyncTask that is supposed to check the network access to a host name. 我有一个AsyncTask应该检查网络访问主机名。 But the doInBackground() is never timed out. 但是......

技术盛宴
52分钟前
18
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部