1

我面临以下问题。

我正在为(比如说)人类信息创建一个数据库。所有的人都可以归为以下三类之一:成年女性、成年男性、儿童。很明显,“身高”和“体重”等参数适用于所有类别。参数“子女数”仅适用于成人,而参数“怀孕数”仅适用于女性。此外,每个参数可以根据类别分为强制或可选(例如,对于成年人,参数“前伴侣的数量”是可选的)。

当我加载(比如说)“身高”和“体重”时,我会检查这两个字段中的信息是否是自洽的。即,我将 height=6'4'' 和 weight=10 lb 的记录标记为错误(显然,这在物理上是不可能的)。我有几个类似的验证规则。

当我插入关于一个人的记录时,我需要反映信息的以下特征:

  1. 此特定人的类别的最大可能信息(包括所有可选参数)。
  2. 类别所需的最少信息(即,仅限必填字段)
  3. 为这个特定的人实际插入的内容(即,可以插入我为这个人所拥有的任何内容,无论它是否小于所需的最少信息量)。这里的重要问题是字段“XXX”可能具有 NULL 值,因为我从未在其中插入任何内容,或者因为我故意插入了 NULL 值。具有默认值的字段的逻辑相同。所以应该在某个地方反映出我已经处理了这个特定的字段。
  4. 已验证插入的信息量(即,即使我加载了大约 5 个字段,我也只能检查 3 个字段的自洽性,而忽略剩下的 2 个字段)。

所以我的问题是如何在技术上组织它。目前,所有这些必需的功能要么被硬编码,没有统一的逻辑,要么被分解成完全独立的块。我需要创建一个统一的方法。

在这方面,我脑子里有一些幼稚的想法。例如,对于每个类别的人,我可以创建并存储可能字段的列表(我称之为“模板”)。A 可以标记那些必填字段。

当我插入关于一个人的记录时,我会复制模板并标记该模板中的哪些字段实际上已被处理。在下一阶段,我可以在此模板副本中标记当前将验证的那些字段。

验证模块通过以下方式进行了特别修正:对于每个验证程序,我创建一个在此特定验证程序中使用的字段列表。然后,我只调用那些在模板副本中实际标记为“待验证”的字段的验证过程,以供要验证的特定人员使用(参见前面的段落)。

如您所见,这是解决此问题的最直接方法。但我的猜测是,有很多我不知道的非常标准化的方法。我真的怀疑我是世界上第一个解决这样一个问题的人。我不喜欢我的解决方案,因为编写代码以在这个复制的模板中正确反映记录中发生的所有“更新”真的很痛苦。

所以,我请你分享你的意见,你将如何解决这个问题。

4

3 回答 3

2

我认为这里有两个问题:

  • 如何在数据库中存储多态数据?
  • 如何验证复杂的业务规则?

您应该分别解决它们 - 尝试同时解决这两个问题可能太难了。

在 RDBMS 中有几种处理多态数据的方法——例如,ORM 使用术语继承映射。这里的三个解决方案——每个类层次结构的表、每个子类的表和每个具体类的表——是“纯”关系解决方案。您还可以使用“实体-属性-值”设计,或使用文档方法(以 XML 或 JSON 等结构化格式存储数据)——这些不是“纯粹的”关系选项,但有它们的位置。

验证复杂的业务规则通常是使用规则引擎完成的——这些是非常酷的技术,但你必须确保你的问题真的适合他们的解决方案——决定投资规则引擎意味着你的项目变成了规则引擎项目,而不是“人类”项目。或者,大多数主流解决方案都在应用程序的业务逻辑层中体现了有关实体的业务逻辑。听起来你已经超越了这个。

于 2013-03-26T18:40:54.093 回答
1

这个确切的问题,无论是在健康方面还是在金融工具方面,都在 Martin Fowlers 的《分析模式》一书中用作主要示例。这是一个广泛的话题。正如@NevilleK 所说,您正在尝试处理两个问题,最好分别处理它们。解决这些问题的一种超简化方法是:

1 多态数据的存储——只在类别表中放入类别共有的强制性数据。对于可选数据,将它们放在一个单独的表中,与类别表呈 1-1 关系。仅当有要记录的值时,才会在这些可选表中输入条目。数据验证的记录也可以放在这些附加表中。

2 验证复杂的业务规则——考虑可能出现的错误类型很有用。有多种方法可以对错误进行分类,但我发现最有用的一种方法是 (a) 类型错误,仅通过查看数据就可以判断该值是错误的 - 例如 1980-02-30。(b) 上下文错误,其中人们只能通过参考先前捕获的日期来检测错误 - 例如,出生日期 1995-03-15,结婚日期 1996-08-26。(c) 对系统撒谎——数据类型正常;上下文还可以;但是只有在以后有更多信息曝光时才能检测到该信息是不正确的,例如,如果我将我的 DoB 注册为 1990-12-31,此时它是不同的。后一类错误通常必须由正在开发的系统之外的程序处理。

于 2013-03-26T20:16:11.817 回答
0

我会使用派对角色模式(Silverston):

Party
id
name

Individual : Party
current_weight
current_height

PartyRole
id
party_id
from_date
to_date (nullable)

AdultRole : PartyRole
number_of_children

FemaleAdultRole : AdultRole
number_of_pregnancies

Postgres 有一个时间扩展,这样你就可以强制一个方一次只能扮演一个角色(但保持他们的角色历史)。

使用表继承。为简单起见,使用单表继承(有空值),没有空值使用类表继承。

于 2013-03-26T19:24:44.857 回答