画出关系
另有 28 种语言版本
English · Español · 日本語 · Português (Brasil) · Français · Deutsch · Italiano · 한국어 · Português (Portugal) · 繁體中文 · Bahasa Indonesia · Türkçe · Polski · Tiếng Việt · ไทย · Nederlands · العربية · עברית · Українська · हिन्दी · Русский · Svenska · Dansk · Norsk bokmål · Suomi · Español (México) · Français (Canada) · Deutsch (Schweiz)

第 2 个模块,共 6 个,属于 Data Architect 课程第 2 章为含义建模数据。每个模块都可以单独阅读。 上一篇:聆听名词 · 下一篇:构建逻辑模型
**本模块回答的问题:**如何把候选实体变成一个概念数据模型?
名词已经上了白板。现在我想了解的是方框之间的连线,因为一堆实体还不算真正的数据模型。很多含义就存在于关系之中。一个零售合作伙伴运营着若干配送中心。一份装货清单列出若干配送。一次配送送达一位收货人。一个配送小组驾驶一辆卡车。每一句陈述都告诉我关于业务的一些东西,每一句也都给了我另一个要问的问题。
从业务语言开始
Section titled “从业务语言开始 ”我仍然不想谈 Salesforce。我不是在问这应该是查找关系还是主从关系,不是在考虑 Salesforce 联接对象(Junction Object),也不是在决定父记录被删除时会发生什么。我是在努力理解业务上的关系。
拿**“一个零售合作伙伴运营着若干配送中心”**来说。听起来很简单。但一个零售合作伙伴有一个配送中心还是多个?在 Steve Trucking,每个零售合作伙伴在 Steve Trucking 服务的每个区域都运营着一个区域配送中心,所以是多个。一个配送中心可以属于多个零售合作伙伴吗?配送中心本身是否重要,有自己的员工和历史,还是只是一个地址?如果某个零售合作伙伴离开了,我们还在意它的配送中心吗?
这些不是 Salesforce 问题,而是业务问题,而答案可能彻底改变模型。
在深入之前,我想先给你一套从现在起每张图都会用到的语言。它很小。两个方框之间的一条线表示这两样东西相关,线两端的标记表示有多少。
从一条普通的线开始,没有任何标记。这是我在白板上的起点:我知道这两个名词相关,只是还没问怎么相关。然后线的两端加上标记。横穿线条的一道短竖线,也就是那个十字,表示一。鸦爪,也就是像鸟爪一样分成三叉的那一端,表示多。在本模块后面,你会看到第一个标记旁边出现第二个标记,一道竖线或一个圆圈,它回答的是另一个问题:可以没有吗?
要记住的唯一规则:**每个标记都在它所接触的方框那一端来读。**离方框最近的标记表示最多可以有多少;往外的下一个标记表示最少有多少。
坐下、别动、建模
Section titled “坐下、别动、建模 ”在讲 Steve Trucking 之前,先回到模块 1 里的狗。我们有五个方框:主人、繁育者、狗、品种和技能。现在我要问它们之间的连线。
**一个还是多个?**一位主人可以有不止一只狗;Ana 就有两只。一只狗只有一位主人,至少在我们的模型里是这样。这就是一对多:主人一端画一道竖线,狗一端画鸦爪。繁育者也是同样的形状:一个繁育者繁育很多只狗。
**可以没有吗?**Max 来自收容所,所以他根本没有繁育者。繁育者一端加一个圆圈:一只狗有零个或一个繁育者。不过每只狗都有主人,所以那一端再加一道竖线:恰好一个。
**多对多?**一只狗会很多项技能,而一项技能,比如坐下,有很多只狗会。这就是多对多,而这正是我去寻找隐藏概念的地方。关于这只狗会这项技能,有没有什么要说的?她做得有多好,什么时候学会的。这个关系有它自己的事实,所以它成了一个独立的事物:狗狗技能(Dog Trick),狗的名字放在前面,因为驱动它的是狗。
**每条线是什么意思?**主人拥有一只狗。繁育者繁育它。一只狗会它的技能。给连线起好名字,任何人都能把模型读回给你听。
现在,还是随时间变化?有没有人在意 Bella 今天坐下做得有多好,或者她是怎么练到这一步的?如果训练师每隔几个月检查她一次,每次检查就是一条独立的记录:一条技能评估(Trick Assessment),带有日期、熟练程度和检查人,归属于它所属的那条狗狗技能。即使是一个已经变成事物的关系,也可以有它自己的历史。
品种我暂时不连线。它仍然是模块 1 留下的那个问题:是一个独立的方框,还是狗身上的一个词,模块 4 会解决它。
这些问题中的每一个,放到真实的业务上都同样适用。现在我们拿它们来问 Steve Trucking。
问“一个还是多个?”
Section titled “问“一个还是多个?” ”关于一个关系,我最先想了解的事情之一是它的基数。这是数据库术语;问题本身要简单得多:**这边的多少个可以与那边的多少个相关?**在概念层次上,有三种基本模式。
这是整个过程中重要的一步:拿两个不同的名词,理解它们之间的关系。在大多数情况下,它是一对多或多对一。只有在少数情况下,你才会碰到一对一。
一对多无处不在。一个零售合作伙伴有多个配送中心。一份装货清单列出多次配送。一条路线有大约十个停靠点。听到这样的话,我就开始画线。
现在这条线有了标记。每一端都说明它所接触的方框有多少:竖线表示一,鸦爪表示多。从每个方框出发去读:一个零售合作伙伴有多个配送中心。
一对一关系是存在的,但很少见,一旦发现,我会问一些问题。这真的是两个不同的名词,还是同一个?如果是不同的,它们之间的一对一关系是什么?它会永远是一对一,还是只是现在一对一?这些都是设计数据模型时的关键问题。在任何一个早上,配送小组和卡车看起来都是一对一的:两个人,一辆卡车,一条路线。但放到一个月里看就不是了,而这个模型里最有意思的关系正藏在那里。
多对多关系特别有意思,因为它们常常告诉我们业务中还有另一个概念。一个配送小组会在一段时间里开不止一辆卡车吗?会。一辆卡车会由不止一个配送小组驾驶吗?在它的整个使用期内,当然会。所以配送小组和卡车是多对多关系。但现在我想了解更多。业务方是否在意某个配送小组什么时候开过某辆卡车?为哪条路线,在哪一天?是谁做的分配?如果关系本身承载着我们在意的信息,我们就发现了另一个业务概念:配送小组分配(Crew Assignment)。
这是一个重要的建模习惯。有时最有意思的东西并不是我们最初听到的某个名词,而是藏在两个名词之间的关系里。
关系可以变成事物
Section titled “关系可以变成事物 ”这是我希望管理员开始换个角度思考的地方之一。在 Salesforce 里,我们习惯谈论对象和字段,所以很容易把方框当成重要的部分,把连线当成管道。但关系本身可以有业务含义。
想想一次配送和它所载的产品。一次配送可以载好几种产品,比如一台洗衣机和一台烘干机。一种产品,比如同一型号的冰箱,会出现在成千上万次配送中。这很简单。但如果我需要知道这次配送里有几台这种产品、是否要安装、是否要把旧的拉走呢?我感兴趣的就不再只是配送和产品之间的关系了。我感兴趣的是一个配送项目(Delivery Item),而这个概念值得拥有自己的实体。
如果你有 Salesforce 背景,你可能已经在想:“这是个联接对象。”你没错。但我不想从那里开始。**配送项目先是一个业务概念,然后才是一个 Salesforce 联接对象。**业务在先,实现在后。
对于这类关系实体,不管最后在哪里构建,我都有几个习惯。
给它起名字。如果业务方已经有一个词,就用他们的。如果没有,就把两个父实体的名字拼在一起。想想订单和产品。它们之间的东西是 Order Item(订单项目):订单,以及订单上的项目。它同时是两个父实体的子实体,在 Salesforce 里最后可能成为一个 Salesforce 联接对象。但哪个名字放在前面:Item Order,还是 Order Item?看看每个父实体是哪类数据。产品是参考数据;订单是交易数据,而驱动它的是订单。所以是 Order Item,或者 Order Product,就像 Salesforce 有 Opportunity Product(业务机会产品)一样。在 Steve Trucking,它是配送项目(Delivery Item)。起驱动作用的名字放在前面,这样在你将来看到的每一个列表里,这条记录都会排在它的所有者旁边。
**给它自己的键。**人们很容易说配送项目由配送加产品来识别,然后就此打住。那是一个复合键,而复合键要难处理得多:每个指向这条记录的系统都得带着两半。给关系实体一个自己的标识符,把配送加产品作为一条关于唯一性的规则,而不是作为身份。
注意它上面没有什么:序列号。数量和序列号不属于同一条记录。数量统计的是某样东西的若干件;序列号识别的是某一件特定的东西。如果业务需要序列号,每一件就成为自己的一条记录,五台冰箱就是五条记录。我想不出有什么理由让配送项目下面再挂一个配送项目明细。要么是这个,要么是那个:带数量的汇总,或者每件一条记录。这里用的是数量。
**留意想要历史的属性。**有些关系实体一旦创建就定下来了:这次配送里的洗衣机,就一直是这次配送里的洗衣机。另一些则不断变化。一个配送小组这周开 117 号卡车,下周这辆卡车就归了另一个小组。当关系会变化,而业务又在意它过去是什么样时,这个关系实体就需要日期,而配送小组分配正是需要留意的那一个。尽早问业务方在意的是现在还是随时间变化;我们马上会回到这个话题。
关系的含义不止于基数
Section titled “关系的含义不止于基数 ”光说“一对多”不足以理解一个关系。我还想知道这个关系意味着什么。
一次配送有一个地点。哪一个?它出发的配送中心?还是它送达的收货人家里?这两者不能互换。两个模型可以有完全相同的方框和完全相同的基数,而连线却可以意味着完全不同的东西。这就是为什么好的模型不只是用线连起来的方框。**连线需要名字。**如果我把图交给另一位架构师,他们不应该需要去猜一个关系是什么意思;如果我拿给业务方看,它应该使用他们认得的语言。
可选性同样重要
Section titled “可选性同样重要 ”“有多少?”里还藏着另一个问题:这个关系是必需的吗?一次配送能在被排上路线之前存在吗?必须能:装货清单在配送前一两天到达,而路线要到前一天晚上才最终确定。一次配送能在没有零售合作伙伴的情况下存在吗?不能;每一次配送都来自某个合作伙伴的装货清单。这就是可选性。
同样,不要直接跳到 Salesforce 的必填复选框。说“每次配送都必须有一个零售合作伙伴”和说“Salesforce 应该在创建记录时要求填写零售合作伙伴字段”是有区别的。它们最后可能是同一种实现,但不是同一句话。前者是一条业务规则;后者是执行它的一种方式。作为架构师,我们要先理解前者,再决定后者。
在图上,可选性是每一端的第二个标记。离方框最近的标记表示最多可以有多少:竖线表示一,鸦爪表示多。往外的下一个标记表示最少有多少:又一道竖线表示至少一个,一个圆圈表示可以是零。所以每次配送都恰好在一份装货清单上,而一份装货清单列出一次或多次配送。一次配送位于零个或一个停靠点,在排上路线之前没有停靠点,而一个停靠点卸下零次或多次配送。
时间会改变关系
Section titled “时间会改变关系 ”有一个问题我经常问:你说的是现在,还是随时间变化?
一个配送小组驾驶一辆卡车。是现在吗?是为了今天的路线吗?还是在这两个人共事的整个期间?这会产生不同的模型。如果业务方只在意一个小组今天开的是哪辆卡车,模型可以保持简单。如果需要知道一个小组开过的每一辆卡车、什么时候、在哪条路线上,我们就需要历史,而我们发现的那个配送小组分配突然就变得非常重要了。
这是建模错误的一个常见来源。我们为当前状态建模,因为那是我们在屏幕上能看到的。然后,几周后,某个零售合作伙伴提出一起货损索赔,有人问:“3 月 17 日是哪个小组开的 117 号卡车?”于是我们发现,每次分配变化时,我们都把答案覆盖掉了。
保留这种历史的一种方法,是让分配成为一条独立的记录。给某个小组分配时,我们创建一条带开始日期的配送小组分配。分配变化时,我们给旧记录加上结束日期,再创建一条带自己开始日期的新记录。现在,“六个月前是谁负责那项分配?”就成了一个简单的问题,而不需要去翻字段历史记录或数据变更日志。而一旦某个小组有过很多次分配,就会有人问哪一次是当前的,所以我还会加一个 Active(有效)标志。
所以,当有人告诉我一个关系时,我不只问这些东西如何相关。我会问:这个关系会变化吗?我们在意它的历史吗?
先画图,再配置
Section titled “先画图,再配置 ”我们的 Steve Trucking 模型正在变得有用。我们知道哪些关系是一对多,多对多关系在哪里藏着另一个概念,哪些关系是可选的,哪些会随时间变化。而我们仍然没有创建任何 Salesforce 对象。这是有意的。
这张图应该是我可以摆到业务方面前的东西,而且他们不需要了解 Salesforce 就能告诉我它对不对。如果因为图里满是 Salesforce 术语而导致他们无法验证,那我就过快地进入物理设计了。
架构师在这里决定什么
Section titled “架构师在这里决定什么 ”在梳理概念模型中的关系时,我要决定的是:
- 主要的业务实体彼此如何关联。
- 每个关系现在以及随时间变化后,是一对一、一对多还是多对多。
- 每个关系是必需的还是可选的。
- 某个多对多关系是否藏着一个有意义的业务概念。
- 关系是否随时间变化,以及我们是否需要它的历史。
查找关系还是主从关系、联接对象的配置、级联行为和共享,这些都是物理层面的决定;我们会讲到。现在我们仍在回答那个更重要的问题:这个业务实际上是如何运作的?一旦理解了实体以及它们之间的关系,我们就可以开始添加描述它们的细节。那时,我们的概念模型就开始变成一个逻辑数据模型了。
