我认为为所有标记分配使用一个表没有任何问题(与多个表相反 - 每个可标记实体一个表)。
然而,你设计中的一个重要细节对我来说仍然是模棱两可的:如果你打算有一些类似的东西
- - - - - - - - - -
Tag
ID // PK
Name
...
- - - - - - - - - -
Taggable
ID // PK
...
- - - - - - - - - -
TagAssignment
Tag_ID // FK -> Tag.ID
Taggable_ID // FK -> Taggable.ID
...
- - - - - - - - - -
EntityOne
Taggable_ID // FK -> Taggable.ID
...
- - - - - - - - - -
EntityTwo
Taggable_ID // FK -> Taggable.ID
...
那么您的实体类是否将拥有自己的主键,或者您将使用EntityOne.TaggableID
and作为andEntityTwo.TaggableID
的事实上的主键?EntityOne
EntityTwo
在大多数情况下,我会谨慎并让实体拥有自己的 ID:
- - - - - - - - - -
EntityOne
ID // PK
Taggable_ID // FK -> Taggable.ID (Nullable)
...
- - - - - - - - - -
EntityTwo
ID // PK
Taggable_ID // FK -> Taggable.ID (Nullable)
...
这不会要求每个实体都有相应的实例,Taggable
因此也不会要求与实体相关的每段代码也都知道标签。但是,如果标记将在系统中真正无处不在,并且如果您确定不需要任何其他实体的“共同祖先”(即,除了Taggable
),那么您可能会在没有“内在”的情况下逃脱实体的 ID。
注意:我从来没有尝试过实现这样的东西,所以我所有的建议都是纯理论的。所以如果我没有看到一些明显的缺陷,请不要拍我。:-)
回应比尔·卡尔文的评论:
你是对的:上面描述的设计并没有阻止多个实体引用同一个Taggable
. 但:
就像我说的,一切都取决于要求。如果我们确定它将Taggable
成为实体的唯一“共同祖先”,那么可以将Taggable_ID
FK 用作实体的 PK。但是,例如,如果某些恰好是“可标记”的实体也必须是“可观察的”(想想通知、通知时间表等)或“任何可以的”:-) 怎么办?我们可以通过将任何实体与任何实体紧密联系来切断所有这些“能力”Taggable
吗?
如果你真的想对一个可标记的实体约束进行数据库级别的强制...... AFAIK,至少有一种常见的方法可以做到这一点而不使 FK 充当 PK:通过引入可标记的“类型”(其中无论如何可能对其他一些功能有用)。
类似这样的东西会让我们吃蛋糕并吃掉它:
- - - - - - - - - -
Taggable
ID // PK
Type
...
- - - - - - - -
Constraint: (ID, Type) is unique
- - - - - - - - - -
EntityOne
ID
Taggable_ID
Taggable_Type // Constraint: always = 'EntityOne'
...
- - - - - - - -
FK: (Taggable_ID, Taggable_Type) -> (Taggable.ID, Taggable.Type)
当然,所有这些都比将实体绑定到可标记对象要复杂得多。但我只是想讨论在我的拙见中,除了原始问题提供的狭隘图片之外,还应该考虑什么。