0

我有一个系统,用户可以在其中声明各种类型的对象-

Teams, 
Facilities, 
Equipment, 
Personnel

用户由“单元”表示——组织馅饼的一个独立切片。在为这些对象之一创建声明后,他们可以设置声明的状态。看起来很简单,对吧?

好吧,这就是头痛的开始。如上所述,这些东西形成了一个松散的层次结构。超级用户使用少量链接表为每个对象创建模板。团队可以由设施、设备和人员组成,设施由设备和人员组成,单元可以为他们想要的任何东西创建索赔。非常灵活,但在后端很烦人。

团队、设施、设备和人员具有完全相同的列:

Id, 
Name, 
Description, 
DateCreated, 
CreatedById, 
IsArchived

为了与 ORM 概念保持一致,现在每一个都是一个单独的表。当用户需要创建声明时,真正的痛苦就来了。层次结构将为我们留下以下表格:

TeamClaim, FacilityClaim, EquipmentClaim, PersonnelClaim, TeamFacilityClaim, 
TeamEquipmentClaim, TeamPersonnelClaim, so on and so forth.  

加上每个这些索赔表的另一个状态表。

显然,这只是垃圾。

因此,我将设计更改为一个名为 ClaimableItem 的表。它具有上述定义的列,以及“类型”列;这只是一个三个字母的表示。然后我创建了一个名为Claim 的表——它包含所有必要的列,并具有定义为ClaimableItemId 和ClaimableItemType 的复合唯一键。

我已经用我的 C# 代码对此进行了测试。EF4 可能讨厌重复使用密钥,但是一个小的解决方法(hack)使它相对容易完成;我可以在大约一个小时内更改我的所有模型、视图和控制器代码以适应新内容。

我的问题(最后)是这样的:我的新单桌设计是废话吗? 它使我的数据库不会被表弄得乱七八糟,实际上会加快添加新的 ClaimableItem 类型——无需为它们创建新对象。我的问题是,三个字母的表示不直观,值得一废,必须在代码中处理,这对我的纯粹主义者有点恼火。

任何人都有更好的想法如何做到这一点?

4

2 回答 2

1

首先,你有一些错误的假设。

  1. 以任何特定方式创建表都不是“与 ORM 概念保持一致”。
  2. 没有必要为每种类型都有单独的表
  3. 没有必要到处都有链接表

大多数 ORM 支持一种使用列鉴别器的继承形式,通常是某种类型的类型值,这与您提出的解决方案相同。

这是设计数据模型和数据库的一种非常实用和实用的方法,但它并不完全是“纯粹的”数据库设计概念,因为您可以再使用引用完整性和约束来确保只有某些值意味着某些东西。

例如,当您有一个 TeamClaim 链接表时,您可以(通过使用参照完整性)保证加入的每个值都是一个团队和一个声明,因为它们是数据库中不同的实体。

如果您打算将团队和索赔联系起来,但将设施和索赔联系起来,会发生什么?哎呀。并且数据库无法知道您犯了错误。

这类似于一个真正的查找表问题。

但是,对于许多人来说,失去参照完整性只是为获得更大的灵活性而付出的很小的代价。你只需要在你的代码中非常小心,不要让人们手动弄乱表格。

于 2013-01-14T22:38:28.010 回答
0

听起来像是继承的一个很好的例子。有Teams, Facilities, Equipment, Personnel继承ClaimableItemClaim参考ClaimableItem

这实际上与您的建议非常相似。你说:

因此,我将设计更改为一个名为 ClaimableItem 的表。它具有上述定义的列,以及“类型”列;这只是一个三个字母的表示。然后我创建了一个名为Claim 的表——它包含所有必要的列,并具有定义为ClaimableItemId 和ClaimableItemType 的复合唯一键。

我认为您不需要复合外键。它们Type的鉴别器列可以坐在ClaimableItem表中。

这是的吗?我认为是这样。这是继承的完美案例。

最后的评论:在这种情况下,请凭直觉。如果您觉得解决方案很糟糕,并且您发现自己希望得到更简单的解决方案,那就去做吧。权衡有时是不明确的选择,随着时间的推移,开发人员学会本能地判断什么是长期正确的。

于 2013-01-14T22:24:00.137 回答