例
我有Person
,SpecialPerson
和User
.Person
并且SpecialPerson
只是人 - 他们在站点上没有用户名或密码,但是它们存储在数据库中以便保存记录.用户拥有所有相同的数据,Person
并且可能SpecialPerson
与在站点中注册的用户名和密码一起使用.
你会如何解决这个问题?您是否有一个Person
表存储一个人共有的所有数据并使用密钥查找他们的数据SpecialPerson
(如果他们是特殊的人)和用户(如果他们是用户),反之亦然?
看看Martin Fowler的企业应用程序架构模式:
单表继承:
映射到关系数据库时,我们尝试最小化在多个表中处理继承结构时可以快速挂载的连接.单表继承将继承结构的所有类的所有字段映射到单个表中.
类表继承:
您希望数据库结构能够清晰地映射到对象,并允许在继承结构中的任何位置链接.类表继承通过在继承结构中为每个类使用一个数据库表来支持此功能.
具体表继承:
从对象实例的角度考虑表,一个明智的路径是将每个对象放在内存中并将其映射到单个数据库行.这意味着具体表继承,其中有一个表用于继承层次结构中的每个具体类.
通常有三种将对象继承映射到数据库表的方法.
您可以使用所有对象的所有字段创建一个大表,并为该类型指定一个特殊字段.这很快但浪费空间,尽管现代数据库通过不存储空字段来节省空间.如果您只是在寻找表中的所有用户,那么每个类型的人都会变得很慢.并非所有or-mappers都支持此功能.
您可以为所有不同的子类创建不同的表,其中所有表都包含基类字段.从性能角度来看,这是可以的.但不是从维护的角度来看.每次基类更改时,所有表都会更改.
您也可以像建议的那样为每个类创建一个表.这样,您需要连接才能获取所有数据.所以性能较差.我认为这是最干净的解决方案.
您想要使用的内容当然取决于您的情况.没有一个解决方案是完美的,所以你必须权衡利弊.
如果用户,人和特殊人都有相同的外键,那么我会有一个表.添加一个名为Type的列,该列被限制为User,Person或Special Person.然后基于Type的值对其他可选列有约束.
对于目标代码,如果您有单独的表或多个表来表示多态,那么它没有多大区别.但是,如果必须对数据库执行SQL,则如果在单个表中捕获多态,则更容易...如果子类型的外键相同.
我将在这里说的是将数据库架构师发送到conniptions,但是这里是:
将数据库视图视为接口定义的等效物.表格相当于一个类.
因此,在您的示例中,所有3个人类都将实现IPerson接口.所以你有3个表 - 一个用于'User','Person'和'SpecialPerson'.
然后有一个视图'PersonView'或任何从所有3个表中选择公共属性(由'interface'定义)到单个视图中的视图.在此视图中使用"PersonType"列来存储所存储人员的实际类型.
因此,当您运行可在任何类型的人上操作的查询时,只需查询PersonView视图即可.
这可能不是OP想要提出的问题,但我想我可能会把它放在这里.
我最近在项目中有一个独特的db多态性案例.我们有60到120个可能的类,每个类都有自己的30到40个唯一属性集,以及所有类中大约10-12个公共属性.我们决定采用SQL-XML路由并最终得到一个表.就像是 :
PERSON (personid,persontype, name,address, phone, XMLOtherProperties)
包含所有常见属性作为列,然后包含一个大的XML属性包.然后,ORM层负责从XMLOtherProperties读取/写入相应的属性.有一点像 :
public string StrangeProperty { get { return XMLPropertyBag["StrangeProperty"];} set { XMLPropertyBag["StrangeProperty"]= value;} }
(我们最终将xml列映射为Hastable而不是XML文档,但您可以使用最适合您DAL的任何内容)
它不会赢得任何设计奖项,但如果您有大量(或未知)数量的可能类别,它将起作用.在SQL2005中,您仍然可以在SQL查询中使用XPATH来根据存储为XML的某些属性来选择行.这只是一个很小的性能损失.