【DDD】学习笔记-数据分析模型

在 Eric Evans 提出领域驱动设计之前,对企业系统的分析设计多数采用数据模型驱动设计。如前所述,这种数据模型驱动设计就是站在数据的建模视角,逐步开展分析、设计与实现的建模过程。通过对数据的正确建模,设计人员就可以根据模型建立数据字典。数据模型会定义数据结构与关系,有效地消除数据冗余,保证数据的高效访问。由于软件系统的业务功能归根结底是对信息的处理,由此建立的数据模型也可以通过某种编程手段来实现,满足业务需求。

数据分析模型

数据建模过程中的分析活动会通过理解客户需求寻找业务概念建立实体(Entity)。在数据模型中,一个实体就是客户希望建立和存储的信息。这是一个抽象的逻辑概念,位于数据模型的最高抽象层。一个实体不一定恰好对应一个数据表,它甚至可能代表一个主题域。在识别实体的同时,我们还需要初步确定实体之间的关系。由于这个过程与数据库细节完全无关,因而称之为对数据的“概念建模”,建立的模型称之为实体关系模型

经过数十年对数据建模的丰富与完善,这个领域已经出现了许多值得借鉴和重用的数据模型。其中,Len Silverston 的著作《数据模型资源手册》是最重要的模型参考手册。他通过对行业业务的梳理,建立了包括人与组织、产品、产品订购、装运、工作计划、发票等各个主题的数据模型。在确定系统的实体时,这些已有的数据模型可以作为我们的重要参考。

当然,每个软件系统的业务需求必然有其特殊性,除了对已有数据模型的参考,也有一些数据建模方法帮助我们获得实体关系模型。例如通过引入不同的用户视图创建不同的实体关系模型。用户视图的差异取决于业务能力的差异,例如,财务人员的观察视图显然不同于市场人员的观察视角,看到的数据信息显然也有所不同。这就像盲人摸象一般,虽然每个视角得到的实体关系模型只是大象的一部分,然而将这些代表不同人员不同观点的实体关系模型组合起来,就能形成整体的实体关系模型。

实体关系模型是数据建模的开始,目的是让我们可以从一开始抛开对数据库实现细节的考虑,寻找那些表达业务知识的重要概念,并明确它们之间的关系。但对数据模型的分析并不会就此止步,我们必须在分析阶段对实体做进一步细化,形成具体的数据表,并定义表属性,确定数据表之间的真实关系。这时获得的分析模型称之为“数据项模型”。实体关系模型与数据项模型之间的关系如下图所示:

img

在数据建模过程中,越早确定数据库的细节越有利于数据模型的稳定。当今的软件开发,已经不是关系型数据库一统天下的时代。NoSQL 甚至 NewSQL 的诞生,让我们在选择持久化机制时有了更多选择。比较关系数据库和 NoSQL 数据库,前者是严格扁平的结构化数据,后者却是无样式的数据结构(Schemaless Data Structures),结构不同,建立的数据模型自然就有了天壤之别。一旦根据数据模型创建了物理的数据表,再调整数据模型,变化的成本就太高了。因此,究竟选择关系数据库还是 NoSQL 数据库,对确立数据项模型至关重要,我们需要分开讨论。

关系数据库的数据项模型

关系数据库体现了关系模型,形成了一种扁平的结构化数据,这就要求进一步规范数据表的粒度,将实体或主题域拆分为多个遵循数据库范式的数据表,明确一个数据表的主要属性。

数据库范式是面向数据的分析建模活动的一个关键约束。这些范式包括一范式(1NF)、二范式(2NF)、三范式(3NF)、BC 范式(BCNF)和四范式(4NF)。遵循这些范式可以保证数据表属性的原子性、避免数据冗余和传递依赖等。

例如在确定数据项时,该如何考虑避免数据冗余?这就需要合理地设计表以及表之间的关系。

假设一个公司的员工可能同时具有多个角色:运输科的张飞是科室的负责人,他又是供应科的客户,供应科会将运输的任务委托给他;同时,他还是一家大型超市的供应商,负责将货物运输给超市。显然,我们不能在一个数据库中为张飞创建三条冗余的数据记录。运输科主任、供应科客户和超市供应商都是张飞担任的角色,无论他担任了什么角色,他都是该公司的一名员工。

在创建数据模型时,应该将角色属性从员工剥离出去,分别形成数据表 t_employee 与 t_role;又因为员工和角色之间存在多对多的关系,需要引入一个关联表 t_employee_roles。这个数据模型如下图所示:

enter image description here

当数据模型出现多对多关系时,之所以要引入一个关联表,是因为多对多关系会引入数据表之间的交叉关联。这个数据项模型中的 t_employee_role 并无映射的业务概念,引入该表,纯粹是数据库实现细节对模型产生的影响。

有时候,承载多对多关系的关联表也可以具有一些附加的属性,这样的关联表往往代表了业务逻辑中的一个业务概念,例如学生(Student)与课程(Course)之间的多对多关系,可以用课表(Curriculum)关联表来表达。Curriculum 属于学习领域的业务概念,但同时它又能有效解除 Student 与 Course 之间的交叉关联。

有的数据建模者甚至建议针对一对多关系也建立关联表,因为关联表的引入使得这种关系更容易维护。例如产品(Product)和图片(Picture)是一对多关系,直接定义 t_product 和 t_picture 数据表即可,但如果引入 t_product_picture 关联表,就可以在数据库层面更好地维护二者之间的关系。有时,一对多关系体现了父—子关系,例如订单(Order)与订单项(OrderItem),它们之间的一对多关系其实代表了“每个订单项必须是一个也只是一个订单的一部分”。

在确定数据项模型时,还需要考虑访问关系数据库的性能特性,从而决定数据的粒度与分割。通常,需要考虑数据表的规范化,避免设计出太多过小的包含少量数据的数据表。一个数据表的粒度较小,就会导致程序在访问数据库时频繁地在多张小表之间跳转。这个访问过程既要存取数据,又要存取索引以找到数据,导致I/O的过度消耗,影响到整体的性能。因此,数据模型很少具有一对一关系,即使现实世界的概念存在一对一关系,也应该尽量通过规范化将两张表的数据组织在一起,合到一个实体中。例如,我们说一位员工有一个家庭电话号码和工作电话号码,若站在领域概念角度,就应该建模为拥有两个不同电话号码(PhoneNumber)的员工(Employee)对象:

img

数据模型却不能这样建立,因为我们需要考虑分开两张表带来的 I/O 开销。虽然家庭电话号码和工作电话号码都是相同的 PhoneNumber 类型,但却属于两个不同的属性,将它们合并放到 t_employee 数据表,并不会破坏数据库范式。

当然,这种合并并非必然,有时候还需要考虑数据访问的频率。例如一个银行账户,账户地址、开户日期与余额都是规范化的,按理就应该合并到 t_account 物理表中。但是,余额与其他两项属性的访问频率差异极大,为了使 I/O 效率更高,数据的存储更加紧凑,就应该将规范化的表分解为两个独立的表:

enter image description here

NoSQL 的数据项模型

如果数据库选择了 NoSQL,数据项模型会有所不同。由于 NoSQL 数据库是一种无样式的数据结构(Schemaless Data Structures),这使得它对数据项模型的约束是最少的。诸如 MongoDB、Elasticsearch 这样的 NoSQL 数据库,它所存储的 JSON 文档,可以在属性中进行任意嵌套,形成一种能够自由存取的文档结构。所以 Martin Fowler 又将这样的 NoSQL 数据库称之为“文档型数据库”。

当然,即使是没有样式的 NoSQL,也无法做到随心所欲地建立数据模型,尤其针对表之间的关系,同样要受到实现机制的约束。例如在 MongoDB 中,可以选择使用 Link 或 Embedded 来维护关联关系,这时就需要结合具体业务场景来选择正确的关联关系。

假设我们要开发一个任务跟踪系统,需要能够查询分配给员工的任务。采用 Embedded 方式,Employee 数据模型如下所示:

{
  name: 'Kate Monster',
  ssn: '123-456-7890',
  role: 'Manager',
  tasks : [
    { number: '1234', name: 'Prepare MongoDB environment', dueDate: '2019-01-15' },
    { number: '1235', name: 'Import Test Data', dueDate: '2019-02-15' },
  ]
}

如果需要查询员工的任务信息,就可以直接获得内嵌在员工内部的任务数组,无需执行多次查询。这时,选择 Embedded 就是合理的。倘若需要支持如下功能:

  • 显示所有明天到期的任务
  • 显示所有未完成的任务

显然,这两个功能要查询的任务与员工无关,而采用 Embedded 方式建立的数据模型却明确地表达了 Employee 与 Task 之间的父子关系,反而为任务的查询制造了障碍。倘若改用 Link 方式来建立二者之间的关联,情况就完全不同了:

//Tasks
[
    {
        _id: ObjectID('AAAA'),
        number: 1234,
        name: 'Prepare MongoDB environment',
        dueDate: '2017-01-15'
    },
    {
        _id: ObjectID('BBBB'),
        number: 1235,
        name: 'Import Test Data',
        dueDate: '2017-02-15'
    },
]

//Employees
{
  _id: ObjectID('E00001'),
  name: 'Kate Monster',
  role: 'Manager',
  tasks : [
    ObjectID('AAAA'),
    ObjectID('BBBB')
  ]
}

通过 Link 建立的数据模型相当于关系数据库建立的主外键关系,去掉了嵌套关系,任务可以被独立查询,如前所述的功能就变得格外简单。但调整后的数据模型又不利于支持查询员工任务的场景了,它会因为关联的原因导致执行两次查询。

选择 Embedded 或 Link 不仅会影响执行效率和执行的简便性,还可能因为错误的建模方式导致数据的冗余。仍然以前面的任务跟踪系统为例,倘若一个任务可以分配给多个员工,就会从一对多关系变为多对多关系。由于 Embedded 方式是将 Task 的数据直接嵌入到 Employee 中,如果别的 Employee 包含了相同的 Task,就会导致 Task 数据的冗余。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/370261.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python新春烟花盛宴

写在前面 哈喽小伙伴们,博主在这里提前祝大家新春快乐呀!我用Python绽放了一场新春烟花盛宴,一起来看看吧! 环境需求 python3.11.4及以上PyCharm Community Edition 2023.2.5pyinstaller6.2.0(可选,这个库…

房企数字化选型-智慧案场:来访到成交,5大环节缺一不可

在“低增长、低利润、高集中度”的房地产存量时代,数字化成为房企突围的必经之路。但面对预算缩减,哪些数字化场景值得优先投入?又有哪些实践案例经验可以借鉴? 【需求与挑战】 线下案场是房地产营销转化成交的最关键环节&#x…

中国古代初入相补原理

中国古代初入相补原理 赵爽(约182---250年,东汉末至三国时代吴国人),为《周髀算经》做注时记述了勾股定理的理论证明,将勾股定理表述为:“勾股各自乘,并之,为弦实。开方除之&#xf…

Facebook群控:利用IP代理提高聊单效率

在当今社交媒体竞争激烈的环境中,Facebook已经成为广告营销和推广的重要平台,为了更好地利用Facebook进行推广活动,群控技术应运而生。 本文将深入探讨Facebook群控的定义、作用以及如何利用IP代理来提升群控效率,为你提供全面的…

计算机毕业设计 | vue+springboot 教务管理系统(附源码)

1,项目背景 随着我国高等教育的发展,数字化校园将成为一种必然的趋势,国内高校迫切需要提高教育工作的质量与效率,学生成绩管理工作是高校信息管理工作的重要组成部分,与国外高校不同,他们一般具有较大规模…

impala与kudu进行集成

文章目录 概要Kudu与Impala整合配置Impala内部表Impala外部表Impala sql操作kuduImpala jdbc操作表如果使用了Hadoop 使用了Kerberos认证,可使用如下方式进行连接。 概要 Impala是一个开源的高效率的SQL查询引擎,用于查询存储在Hadoop分布式文件系统&am…

图论练习4

内容:染色划分,带权并查集,扩展并查集 Arpa’s overnight party and Mehrdad’s silent entering 题目链接 题目大意 个点围成一圈,分为对,对内两点不同染色同时,相邻3个点之间必须有两个点不同染色问构…

音箱、功放播放HDMI音频解决方案之HDMI音频分离器HHA

HDMI音频分离器HHA简介 HDMI音频分离器HHA具有一路HDMI信号输入,转换成一路HDMI信号、一路5.1光纤音频信号、一路5.1 SPDIF/同轴音频信号和一路模拟左右声道立体声信号输出,同时还支持EDID存储及兼容HDCP功能;分辨率最高支持1920*1080p&#…

【已解决】c++ qt选中该行为什么该列部分变色

笔者开启了QTableView中交替行改变颜色,发现笔者自定义绘制的水平滚动条,在选中后不发生颜色改变,这让笔者很疑惑。笔者查阅资料后发现,自定义绘制的控件,要自身设置颜色。当笔者解决了这个问题时,顺手就将…

视频孪生教育实训平台 助力高校打通产教融合最后一公里

数字孪生成高校产教融合破局点 随着我国经济的高质量发展,产业结构不断进行调整,数字经济已成为一大发展趋势。数字孪生作为推动千行百业数字化转型、促进数字经济发展的重要抓手,被众多企业高度关注,并在工业、能源、城市、交通…

Maven提示Failure to find com.oracle:ojdbc14:jar:10.2.0.4.0

目录 问题 解决方案 1、下载oracle的驱动jar包 2、安装到本地仓库 3、检查本地仓库是否成功安装 4、Maven先clean ,再install。 问题 项目引入Oracle依赖后报错,显示为红色。 解决方案 1、下载oracle的驱动jar包 首先我们要去下载一个oracle的…

【Linux】解决:为什么重复创建同一个【进程pid会变化,而ppid父进程id不变?】

前言 大家好吖,欢迎来到 YY 滴Linux 系列 ,热烈欢迎! 本章主要内容面向接触过Linux的老铁 主要内容含: 欢迎订阅 YY滴C专栏!更多干货持续更新!以下是传送门! YY的《C》专栏YY的《C11》专栏YY的…

2024牛客寒假算法基础集训营1(视频讲解全部题目)

2024牛客寒假算法基础集训营1&#xff08;题目全解&#xff09; ABCDEFGHIJKLM 2024牛客寒假算法基础集训营1&#xff08;视频讲解全部题目&#xff09; A #include<bits/stdc.h> #define endl \n #define deb(x) cout << #x << " " << …

16- OpenCV:轮廓的发现和轮廓绘制、凸包

目录 一、轮廓发现 1、轮廓发现(find contour in your image) 的含义 2、相关的API 以及代码演示 二、凸包 1、凸包&#xff08;Convex Hull&#xff09;的含义 2、Graham扫描算法- 概念介绍 3、cv::convexHull 以及代码演示 三、轮廓周围绘制矩形和圆形框 一、轮廓发现…

插入排序、希尔排序----C语言数据结构

目录 引言 1.插入排序的实现思想1.1插入排序的时间复杂度及优缺分析2.希尔排序的实现思想2.1希尔排序的时间复杂度 引言 插入排序&#xff08;Insertion Sort&#xff09;是一种简单而直观的排序算法&#xff0c;它的基本思想是逐步构建有序序列。在每次迭代中&#xff0c;插入…

LLM应用开发与落地:使用gradio十分钟搭建聊天UI

一、背景 如果你是做LLM应用开发的&#xff0c;特别是做后端开发&#xff0c;你一定会遇到怎么快速写一个聊天UI界面来调试prompt或agent的问题。这时候的你可能在苦恼中&#xff0c;毕竟react.js, next.js, css, html也不是每个人都那么熟练&#xff0c;对吧&#xff1f;即使…

clr的执行模型-笔记

学习来源&#xff1a;《CLR via C by Jeffrey Richter 》第四版&#xff0c;第1章 clr的执行模型 1.C#编译生成执行程序集文件 编译文件的组成&#xff1a;pe32/pe32头&#xff0c;clr头&#xff0c;元数据&#xff0c;IL pe32/pe32头&#xff1a;windows标准执行文件头 cl…

SpringBoot+Vue实现各种文件预览(附源码)

&#x1f468;‍&#x1f4bb;作者简介&#xff1a;在笑大学牲 &#x1f39f;️个人主页&#xff1a;无所谓^_^ ps&#xff1a;点赞是免费的&#xff0c;却可以让写博客的作者开心好几天&#x1f60e; 项目运行效果 前言 在做项目时&#xff0c;文件的上传和预览必不可少。继上…

Acwing---829. 模拟队列

模拟队列 1.题目2.基本思想3.代码实现 1.题目 实现一个队列&#xff0c;队列初始为空&#xff0c;支持四种操作&#xff1a; push x – 向队尾插入一个数 x&#xff1b;pop – 从队头弹出一个数&#xff1b;empty – 判断队列是否为空&#xff1b;query – 查询队头元素。 现…

Unity引擎学习笔记之【动画剪辑和曲线操作】

动画剪辑和曲线Animation Clip 点选一个包含动画的FBX模型&#xff0c;在其检查器中便可查看动画剪辑 一、动画剪辑 1.Model 2.RIg 538.jpg%20%3D600x&pos_idimg-st6QJc3x-1707050419493) 无动画、旧版Animation动画、普通道具或角色动画、人形角色动画 3.Animation 二…