我在这里需要多态关联,还是我的模型不够充实?

时间:2017-08-22 15:18:16

标签: ms-access database-design relational-database polymorphic-associations

我来这里是为了提出一个问题,我在为数据库开发设计的过去几天里一直在喋喋不休。

简介:
该数据库旨在存储关于运动类型的信息(不是关于实际马达,而是关于它们的设计,参数等),它们的组件/属性以及某些运动类型之间的关系(每种运动类型与所谓的基本运动类型相关)。所以我们有几种motortypes,每种都有很多属性(我称之为详细类型)。每个细节类型又可以存在于一个或多个 motortype中。每种motortype:detailtype组合应该(确切地)有一个值 我需要能够比较两种不同motortype的特定detailtype的值,并根据这种比较存储信息。 (存储此信息是数据库的核心目的。)

现在第一个也是最简单的方法是制作一个motortype表并使每个detailtype都有一列,这样我就可以为每个组合存储一个值:

Approach #1:

CREATE TABLE Motortype(
id INTEGER PRIMARY KEY,
description CHAR (50),
detailtype1 CHAR (50),
detailtype2 INTEGER,
detailtype3 YES/NO,
detailtype4 DOUBLE );

将有大约一百个(这个数字可能在将来慢慢增长)这样的详细类型要输入到数据库中。添加更多对应于添加更多列(可管理),更改它们会导致重命名列(不好主意?)。当我想在其detailtype2值上比较motortype与ID 2和5并且保存有关此比较的信息时,会出现问题。我不知道如何管理它。 (此外,属性不能具有NOT NULL约束,因为某些数据在创建条目时可能只是未知...)
这就是为什么我继续接近2,这似乎以某种方式实现了EAV。

为了允许存储比较信息,我将详细类型从属性转移到mototype到他们自己的实体,同时将那些不需要比较的那些作为属性:

Approach #2:

CREATE TABLE Motortype(
 id INTEGER PRIMARY KEY,
 description CHAR (50),
 notComparableAttribute1 CHAR (50),
 notComparableAttribute2 INTEGER
);

CREATE TABLE Detailtype(
 id INTEGER PRIMARY KEY,
 description CHAR (50),
 datatype CHAR (3)
);

CREATE TABLE MotorDetail(
 id INTEGER PRIMARY KEY,
 motortype_id INTEGER CONSTRAINT fk_mt_id REFERENCES Motortype(id) NOT NULL,
 detailtype_id INTEGER CONSTRAINT fk_dt_id REFERENCES Detailtype(id) NOT NULL,
 value CHAR (50) NOT NULL
);

然后,此配置允许我引用MotorDetail中的任何特定值对,并为此比较保存其他信息。 (注意,这个比较还有更多的维度 - 它与MotorDetail没有1:1的关系。相反,它是1:n MotorDetail:ComparisonData关系。否则我可以直接将所有比较信息存储在MotorDetail中。 )
但是,我现在有一个值属性需要保存几种不同的数据类型(字符串,整数,浮点数,布尔值)这一事实意味着输入验证的责任从数据库移动到我(我需要确保用户只能以对各个Detailtype有意义的方式输入数据。这完全没问题 - 它只是一点点编程工作,但我觉得它可以以更优雅的方式解决。

因此,经过对多态关联的一些研究后,我提出了下一种方法(Motortype和Detailtype与#2一样):

Approach #3:

CREATE TABLE MotorDetail(
 id INTEGER PRIMARY KEY,
 motortype_id INTEGER CONSTRAINT fk_mt_id REFERENCES Motortype(id) NOT NULL,
 detailtype_id INTEGER CONSTRAINT fk_dt_id REFERENCES Detailtype(id) NOT NULL,
 valueTxt CHAR (50),
 valueInt INTEGER,
 valueDbl DOUBLE,
 valueBoo YES/NO
);

值属性不能具有NOT NULL约束,因为75%的值将为null(根据要求,每个MotorDetail只能有一个值)。只要我只需要特定数据类型的值,查询值就好了,否则会变得更复杂(例如在表单上显示它们)。或许我应该说乏味而不是复杂。

因此,在最后一次尝试这个问题时,我提出了我的最终方法(再次,Motortype和Detailtype,如#2):

Approach #4:

CREATE TABLE MotorDetail(
 id INTEGER PRIMARY KEY,
 motortype_id INTEGER CONSTRAINT fk_mt_id REFERENCES Motortype(id) NOT NULL,
 detailtype_id INTEGER CONSTRAINT fk_dt_id REFERENCES Detailtype(id) NOT NULL
);

CREATE TABLE MotorDetailValueTxt(
 id INTEGER PRIMARY KEY,
 valueTxt CHAR (50)
);

CREATE TABLE MotorDetailValueInt(
 id INTEGER PRIMARY KEY,
 valueTxt INTEGER
);

... (same for MotorDetailValueDbl and MotorDetailValueBoo)

我不确定这个。不确定如何表示值表中的每个id都与一个MotorDetail(id)相关联的想法,并且需要在所有值表中保持唯一。甚至不确定我完全理解基本概念。但我确信这样做是因为DB不能强制执行参照完整性。这就是我不打算使用它的原因。在测试数据库中,我能够使用UNION生成查询以获取所有不同的值,但我不认为我想在表入口级别进行任何内务处理(以某种方式确保没有死项)。< / p>

问题:

鉴于到目前为止概述的细节,是否有可能的解决方案不涉及某种编码技巧(VBA或其他)?一个优雅的解决方案,以某种方式允许在数据库级别处理这一切(表格+关系,而不是报告,表格等...)?因为我到目前为止所做的一切似乎都很笨重。

注意:我是数据库设计和数据库的新手。我在MS Access中接受了3天的培训,但这主要是为了学习GUI和构建一些非常基本的DB而定制的。关于DB开发的任何其他事情都是通过阅读博客来学习的 - 最重要的是:问题和答案在这里。 似乎可以安全地假设我没有(完全)理解我讨论的一个或多个概念,从而错误地表达了其中的一些概念。如果是这样,或者如果缺少任何其他内容,请在评论中指出或编辑以改进我的问题(并允许我阅读)。 :)

编辑:进行了编辑,并且编辑了一个。我试图添加信息,澄清那里有什么,仍然保留问题的原始特征和意图。让我们希望我至少部分成功。 :)

1 个答案:

答案 0 :(得分:1)

您的问题似乎更简单&amp;基本比你的设计比较。对于给定的应用程序片段而言,这似乎比必要或期望的更复杂。

业务关系(船舶)/关联由表格表示。我们可以通过谓词(列参数化语句模板)来表征关系(发货)/关联/表。表格包含产生真实命题的行 - 语句。

您还没有任何理由让设计更复杂:

-- motor motorID has (non-details) ...
Motor(motorID, ...)
-- motor motorID has NumOfCylinders cylinders
MotorNumOfCylinders(motorId, NumOfCylinders)
-- motor motorID has cylinder material CylinderMaterial
MotorCylinderMaterial(motorId, CylinderMaterial)
...

你只想要一张电动机台吗?

--      motor motorID has (non-details) ...
--  AND motor motorID has NumOfCylinders cylinders
--  AND (   NumOfCylinders > 0 and motor motorID has cylinder material CylinderMaterial ...
--      OR  NumOfCylinders = 0 and CylinderMaterial = NULL ...
--      )
...
-- PK (motorID)
Motor(motorId, ..., NumOfCylinders, CylinderMaterial, ...)

您还没有解释随着时间的推移会发生什么变化。您想要更改字符串与给定详细信息的关联吗?对于可选字符串:

-- detail "NumOfCylinders" is written NumOfCylinders
NumOfCylindersString(NumOfCylinders)
-- detail "CylinderMaterial" is written CylinderMaterial
CylinderMaterialString(CylinderMaterial)
...

你想要一张这样的桌子吗?对于强制性字符串:

--     detail "NumOfCylinders" is written NumOfCylinders
-- AND detail "CylinderMaterial" is written CylinderMaterial
...
DetailStrings(NumOfCylinders, CylinderMaterial, ...)

您是否明确需要不同种类/类型的电机,以便在处理特定种类/类型时有静态约束?

-- motor motorID ... and has NumOfCylinders cylinders and weighs Weight kg and ...
Motor(motorId, ..., NumOfCylinders, Weight, ...)
-- piston motor motorID has cylinder material CylinderMaterial ...
PistonMotor(motorId, CylinderMaterial, ...)
--       electric motor motorId has ...
--   and it is isAC that it takes AC current
--   and it is isDC that it takes DC current
...
ElectricMotor(motorId, isAC, isDC, ...)
...

您是否希望以冗余和成本为代价将电机限制为一种类型/类型。计算

-- motor motorId is of type motorType and ...
Motor(motorId, motorType, ...)
-- PistonMotor enforce (motorId, 'piston') in (select motorId, motorType from Motor)
-- ElectricMotor enforce (motorId, 'electric') in (select motorId, motorType from Motor)
...

您是否希望以不同的成本权衡(通过存储或生成的列值)进行声明性约束?

-- motor motorID has type motorType and motorType = 'piston' and cylinder material CylinderMaterial ...
-- FK (motorID, motorType) references Motor (motorID, motorType)
-- check (motorType = 'piston')
PistonMotor(motorId, motorType, CylinderMaterial, ...)
-- motor motorID has type motorType and motorType = 'electric' and ...
-- FK (motorID, motorType) references Motor (motorID, motorType)
-- check (motorType = 'electric')
ElectricMotor(motorId, motorType, isAC, isDC, ...)
...

更多?

-- Motor check (NOT (motorType = 'electric' AND NumOfCylinders <> 0))

细节可以随时间变化吗?你想随着时间的推移得到不同的细节吗?您可以使用DDL来实现更改。您想知道目前有哪些详细信息或详细信息值?查询元数据。或者可能有一些非系统表或其轴与1:1的系统表或其轴的行。

你是否以某种方式思考/假设/怀疑/担心实施用户导向的状态变化在某种程度上通过DML比DDL更好,但是以复杂性为代价。处理? DDL更新实现是否显示太慢?您可以通过EAV部分或完全编码这些数据库状态及其相应的专业人员和缺点

  

EAV&#39;数据库&#39; [sic] 字面上 数学 直接数据库及其元数据三元组中的未记录描述,没有任何功能

  

要解释Greenspun,任何足够复杂的EAV项目都包含一个特殊的,非正式指定的,错误缠身的,一半DBMS的缓慢实现。

(观察一个列在EAV中给出另一个列的类型 - 其中数据对于表示是必不可少的 - 并且在一些子类型惯用语中 - 作为冗余的变体标签并且用于约束。{{ 3}})

给出简单的设计和各种查询&amp;你想要的更新,它可以重新安排到另一个设计。其他设计&#39;基表是基本设计表的视图/查询,反之亦然。

我专门修改了一个设计,以促进更简单的约束表达。每个业务规则可能出现的基本谓词和业务情况决定了可能出现的数据库状态,从而确定了数据库约束。我们不需要知道要查询的约束。