我们如何实现 IS-A 关系?

Posted

技术标签:

【中文标题】我们如何实现 IS-A 关系?【英文标题】:How do we implement an IS-A Relationship? 【发布时间】:2010-12-05 21:39:18 【问题描述】:

我们通过将一个表的 PK 作为 FK 添加到另一个表来实现一对多关系。 我们通过将 2 个 Table 的 PK 添加到第三个 Table 来实现多对多关系。

实体是 TECHNICIAN 和 ADMINISTRATIVE,两者都是 EMPLOYEE。 我可以在表格中使用一个额外的字段 EMPLOYEE(id, name, surname, role, ...AdminFields..., ...TechFields...)

但我想探索 IS-A 选项。

编辑:我按照 Donnie 的建议做了,但没有角色字段。

【问题讨论】:

IS-A 本身并不是一种关系。行的标识通常由包含它的表的名称定义。例如。名为employees IS-A 员工的表中的一行。如果要添加包含TECHINICIANADMINISTRATIVE 等的employee_type 枚举,那很好。但该表中的每一行仍然是员工。 @Asaph - 我认为这意味着映射到子类,例如通过 ORM。在这种情况下,Technician 将是域模型中 Employee 的子类,并且 Technician 和 Employee 实体之间将存在 IS-A 关系。也就是说,我不认为组织中的角色最好使用继承来建模。 @Asaph - 如果 TECHNICIAN 有许多具体属性,而 ADMINISTRATIVE 没有(并且相反),你会怎么做? 【参考方案1】:

我按照 Donnie 的建议做了,但没有 role 字段,因为它使事情复杂化。这是最终的实现:

DDL:

CREATE TABLE Employee (
ast VARCHAR(20) not null,
firstname VARCHAR(200) not null,
surname VARCHAR(200) not null,
...
PRIMARY KEY(ast)
);

CREATE TABLE Administrative (
employee_ast VARCHAR(20) not null REFERENCES Employee(ast),
PRIMARY KEY(employee_ast)
);

CREATE TABLE Technical (
employee_ast VARCHAR(20) not null REFERENCES Employee(ast),
...
PRIMARY KEY(employee_ast)
);

ER图:

在此模型中,没有通用类型的员工。在这里,员工只能是管理人员或技术人员。

【讨论】:

我相信,当您想将员工降级到实际实施中时,保留角色列很有用。如果您有一个员工 ID,并且您想检索他的所有信息。您必须知道要加入哪个 ROLE 表。如果没有角色列,您将需要查找每个角色的表以查看其中是否存在 ID,然后加入它。 或者类似地,给定一个员工 ID,检索他在公司中的角色。我确实觉得很难确保角色列相对于角色表的完整性很难维护。我想知道是否有更好的方法来做到这一点。 更好的方法:创建视图 vwEmployeeRoles 作为选择 ID,“技术员”作为技术人员工会选择 ID 的角色,“管理员”作为管理员的角色【参考方案2】:

IS-A 关系也称为 gen-spec 设计模式。 Gen-spec 是“泛化专业化”的缩写。

gen-spec 的关系建模与 gen-spec 的对象建模不同,因为关系模型没有内置继承。

这是一篇很好的文章,展示了如何将 gen-spec 实现为表的集合。

http://www.javaguicodexample.com/erdrelationalmodelnotes1.html

特别注意在专用表中设置主键的方式。这就是使使用这些表格变得如此简单的原因。

你可以找到很多其他的谷歌“泛化专业化关系建模”的文章。

【讨论】:

【参考方案3】:

我总是使用 role 字段,然后是可选关系来完成此操作。

即表EMPLOYEE (id, ...generic fields... , role)

然后,对于每个角色:

ROLE1 (employeeid, ...specific fields...)

这允许您通过单个查询获取一般员工信息,并且需要连接才能获取特定于角色的信息。这样做的一个(大)缺点是,如果您需要一个包含所有角色信息的超级报告,那么您会遇到一堆外部连接。

【讨论】:

当我在 EMPLOYEE 实体和其他表 ROLE(employeeid,roleType) 中添加“角色”时,假设两个是 2 个数据仅为 Worker 的“W”。 'T' 代表技术人员,这是一种冗余??【参考方案4】:

如果您有一个需要连接到关系后端数据库的 OO 应用程序,我建议您使用 Martin Fowler 的Patterns of Enterprise Application Architecture。

他的网站上也有一些相关的注释和图表。具体来说,Single Table Inheritance、Class Table Inheritance 和 Concrete Table Inheritance 模式描述了在数据表中映射 IS-A 的三种策略。

如果您使用的是 Hibernate 或 JPA,它们支持所有这些的映射,尽管它们的名称不同。

在这种特定情况下,我根本不会使用 IS-A。

像员工角色这样的东西最好建模为 HAS-A,因为

    您可能需要一个人 有多个角色。 改变一个人的角色将是 更容易。

【讨论】:

非脱节的 IS-A 关系可以有多个角色。您可以让员工 ID 同时出现在管理表和技术表中。至少我是这样相信的。考虑到每个角色都有不同的属性集,您将如何处理 HAS-A 关系?您会为每个角色创建一个表吗?但是,您将如何从 Employee 表中引用它?【参考方案5】:

本文描述了将泛化映射到模式设计的一些策略。

http://www.sztaki.hu/conferences/ADBIS/3-Eder.pdf

摘要的副本:

更丰富的数据模型 对象关系数据库打开了许多 逻辑设计的更多选择 数据库模式增加 逻辑数据库设计的复杂性 极大地。注重泛化 我们构建的概念模型 探索性能影响 的各种设计替代方案 将概括映射到 对象关系模式 数据库系统。

【讨论】:

【参考方案6】:

为什么不将其实现为一对零/一个表关系?假设您有一个表,表示名为 Vehicle 的基类,主键为 VehicleID。然后,您可以有任意数量的卫星表来表示 Vehicle 的所有子类,并且这些表也有 VehicleID 作为它们的主键,从 Vehicle->Subclass 具有 1->0/1 的关系。

或者,如果你想让它更简单,并且你确定你只会有几个子类并且改变的可能性不大,你可以在一个表中表示整个结构鉴别器类型字段。

【讨论】:

【参考方案7】:

大多数 ORM 使用单列鉴别器实现 IS-A 关系,根据特定列中的值选择要实例化的子类。关于您的示例,您可能并不是真的指role,因为通常一个人可以担任许多不同类型的角色。角色通常会被建模为 has-a 关系。如果您确实尝试使用 is-a 关系(或子类化)来实现它,那么您不可避免地最终不得不做一些更复杂的事情来处理您有一个人担任混合职位的情况 - 即同时担任本地 IT 人员的秘书,需要两者的权限或属性。

【讨论】:

Hibernate 支持多种不同的继承映射,包括这种带鉴别器的单表策略,但不限于此。我同意将角色更好地建模为 HAS-A。 考虑到每个角色都有不同的属性集,您将如何处理 HAS-A 关系?您会为每个角色创建一个表吗?但是,您将如何从 Employee 表中引用它? @didibus - 使用带有外键的人员和角色的连接表,允许每个人拥有多个角色。如果您需要权限(属性?)的灵活性,您可以在角色和权限之间使用另一个连接表。【参考方案8】:

这取决于您是在构建单层次结构还是多层次结构。这是一个硬编码的设计,我相信这就是你想要的。

对于mono(子表有一个父表),其中child IS-A parent,子表中的FK和PK相同,该key也是父表中的PK。

对于 poly(子表有多个父表),其中子 IS-A parent-1 和子 IS-A parent-2,您将拥有一个复合键(意味着多个主键使表记录唯一),其中规则与每个键的单一层次结构相同。

【讨论】:

以上是关于我们如何实现 IS-A 关系?的主要内容,如果未能解决你的问题,请参考以下文章

IS-A 和 HAS-A

设计模式-UML关系基础

在 C# 中映射 IS-A 关系的正确方法

继承和派生—— 类与类之间的关系继承的基本概念

Java核心技术第四章----对象与类重难点总结

Go语言开发Go语言面向接口