我正在尝试找出将对象模型中的继承关系映射到关系数据库的最佳方法。例如,考虑以下类结构。

public Class Item 
{
    public String Name{get; set;}
    public int Size {get; set}    
}

public Class Widget:Item
{
    public String Color{get; set;}
}

public Class Doohicky:Item
{
    public String Smell{get; set;}
}


以下是我正在考虑的一些选项,用于将这种结构保存到数据库中。

选项1:所有项目类型的单个表格

Items Table: ItemID, Name, Color, Smell


这很糟糕,因为它需要NULL值。

选项2:单独的表格对于每种项目类型

Widgets Table: WidgetID, Name, Color
Doohicky Table: DoohickyID, Name, Smell


这是更好的方法,但要列出所有项目会更困难

选项3:链接表

Items Table: ItemID (PK), Name, Size
Widgets Table: WidgetID (PK), ItemID (FK), Color
Doohicky Table: DoohickyID (PK), ItemID (FK), Smell


我认为此选项是最好的,因为它使我无法在任何字段中使用Null值,而且它将使列出所有Items和/或创建它更容易特定类型的项目(小部件或Doohickies)的列表。

但是,我不确定如何在Items表与Widgets和Doohickies表之间建立关系。我不想最后一个表中的行引用了Items表中的相同ItemID。

例如,当我向Widgets表中添加条目时,如何确保它以唯一的ItemID链接到Items表中的新条目?我是否应该只跟踪ItemID,而不是分别跟踪特定于类型的ID(如WidgetID和DoohickyID),并使用它在Items表和特定于类型的表之间创建一对一关系?

选项4

Items Table: ItemID (PK), Name, Size
Widgets Table: ItemID (PK), Color
Doohicky Table: ItemID (PK), Smell


#1 楼

您正在描述单表继承,具体表继承和类表继承。

请参阅经典的Martin Fowler的《企业应用程序体系结构的模式》一书,以获取有关它们的大量信息。

您可以做一件事情来确保只有一个子类型可以引用超类型是使用ItemType字段。外键可以引用UNIQUE约束的列以及PRIMARY KEY。因此,您可以添加Items.ItemType并对ItemIDItemType进行唯一约束。每个子类型表中的外键均引用此两列唯一键。然后可以将每个子类型表中的ItemType约束为某个值。然后,它必须与只能有一个值的超类型表中的值匹配。

Items Table: ItemID (PK), ItemType, Name, Size
  UNIQUE: (ItemID, ItemType)
Widgets Table: ItemID (PK), ItemType, Color
  FK: (ItemID, ItemType)
  CHECK: ItemType=W
Doohicky Table: ItemID (PK), ItemType, Smell
  FK: (ItemID, ItemType)
  CHECK: ItemType=D


评论


嗯,这很有帮助。我绝对希望遵循“类表继承”模式。

–埃里克·阿纳斯塔斯(Eric Anastas)
2010-09-14 22:31

#2 楼

如果您在设计时考虑到当前的类,出于上述原因,我希望将选项3作为首选选项。

关于:

However, I'm not sure how to create the relationship between the Items table and the
Widgets and Doohickies tables. I don't want to end up with row in either table 
referencing the same ItemID in the Items table. 
的查询

上面的比尔的建议绝对是一个不错的选择。我以前没有想到的事情:-)
但是,我一直在考虑这种关系,您可以在应用程序代码本身中或通过使用Insert触发器来实现。

但是我担心

如果子类的数量预计会在一段时间内增长,则这种DB设计可能会变得非常难以维护。

除了:

Items Table: ItemID (PK), Name, Size        
Widgets Table: WidgetID (PK), ItemID (FK), Color        
Doohicky Table: DoohickyID (PK), ItemID (FK), Smell        


像下面这样添加新类的可能性是什么?
DontDoHicky Table : DoohickyID (PK), ItemID (FK), Smell, **TASTE**        
MidWidget Table : WidgetID (PK), ItemID (FK), Color , **Height**        
MidDoHicky Table : WidgetID (PK), ItemID (FK), **Height**, **Smell**


这当然是经典的面向对象继承问题。 ,您可能更喜欢采用更通用的方法

Items Table: ItemID (PK), Name, Size, **ItemType**        
**ItemAttributes Table : ItemID (PK), AttributeID, AttributeName, AttributeValue**    


,这将使您轻松实施1:1映射的约束,并允许您使用A只要这些是标准名称,就可以使用ttributeName。

这可能是老式的方法,不是非常面向对象的,但根据将来的灵活性,它可能更适合。

#3 楼

您是否考虑过像RavenDB或MongoDB这样的NoSQL解决方案?如果您的需求不完全是关系型的,那么非关系型解决方案可能会大大简化事情。