在对一对一关系进行一些研究时,我遇到了一些让我质疑我的数据库设计决策的陈述。
基本上我有一些类似于以下的实体:
人,联系人,家长
联系人和父母都是人。 一个人可能是联系人,父母,两者或两者都不是。
我想出的数据库设计为这三个实体中的每一个都有一个表,并且所有三个表共享一个主ID(PersonID)。从数据库设计的角度来看,这似乎是一种表示数据库及其关系的良好规范化且性能合理的方式(至少对我而言)。
此时,我开始编写C#类和NHibnerate映射来表示这些实体。我能找到的最自然的映射方法是使用映射。其他选项(一对一,一对多等等)似乎要求我向表中添加一个或多个不必要的FK。在浏览NHibernate文档后,我偶然发现了以下声明:
此功能通常仅对旧版数据模型有用,我们建议使用的表少于类和细粒度域模型。但是,如下所述,在单个层次结构中切换继承映射策略很有用。
我的问题是:
A)我违反了这个原则吗? B)如果是这样,我将如何更好地设计这个系统?
这句话是否表明我应该将所有Person / Contact / Parent字段整合到一个表中(有许多可空字段)?还是我不知何故错过了这一点?
由于这是一个罕见的场合,我可以从头开始设计表/类,我希望能够做到。在此先感谢您的帮助!
编辑:有关我打算如何使用上述数据库设计的更多信息:
基本思想是每个人都在人员表中获得记录。相关表中记录的存在/不存在决定了该人是父母,联系人等......这似乎强制执行一对一关系并允许快速查询/加入(共享主要ID将是每个表中的聚类PK。)
编辑:感谢帮助人员。当我设计这个系统时,我并没有真正考虑可查询性,因此我将采用与Jamie Ide& amp; amp; hlgem。我发现所有答案都有帮助。总而言之,它看起来像共享主键导致c#端对象模型出现一些问题。
答案 0 :(得分:2)
您的数据库设计需要一些工作;这是我的建议。
你知道联系人和家长都可以成为人,这是很好的。但是,您需要Contact和Parent才能拥有不同的主键。您可以强制要求它们在Contact表和Parent表中都具有父级ID和不可为空的外键,这些表引用了Person表中条目的Person ID。
因此Person表应具有唯一的主键(其ID)和任何其他相关列。 Contact表应具有自己唯一的主键(其ID),对Person表的不可为空的外键引用(Person表中的ID)以及任何其他相关列。 Parent表应该有自己唯一的主键(它的ID),以及对Person表的不可空外键引用(Person表中的ID)和任何其他相关列。
这应该可以解决您的映射问题。如果需要,您可以使用View来“重新组合”您的Person / Parent / Contact“constellation”(相关表的集合)。
答案 1 :(得分:1)
你问的是继承映射,而不是一对一的关系。您的设计需要table-per-subclass映射,但我不确定如何解决一个Person既可以是Contact又是Parent的要求。除了介绍另一个涵盖这两个角色的子类之外,我不知道对此进行建模的好方法。可以这样想,如果你要求你的存储库返回一个Person,那个Person既是一个Contact又是一个Parent,它应该返回哪个类型?
如果您坚持继承子类,那么我建议尽可能坚持table-per-class。
但更好的设计可能是引入“角色”表,并在人与角色之间建立一对多的关系。
编辑添加:恕我直言,您当前的设计将无法正常工作。什么类型的对象代表同时是联系人和父母的人?
您可以使用包含其他数据的“复杂”角色表,而不是简单的角色表。您可以拥有一组Role对象(ContactRole,ParentRole等),每个对象都包含与该角色关联的字段。然后,Person对象将具有Role对象的集合。
答案 2 :(得分:1)
其中一些取决于您打算如何查询该数据。如果您希望能够轻松地查看某个人在角色特定的详细信息中扮演的角色,那么请拥有角色表。要查看一个人拥有的所有角色,无论您稍后添加多少个角色,都只需要连接两个表。否则,您将必须加入每个专业表(如果不存在,则为左联接),只是为了查看一个人有什么角色。表现不太好。
我们的数据库中有很多这些类型的关系,我们有一个带有id的person表,一个带有id和角色id的角色表,以及一个角色类表,它是角色的查找。然后是具有特定角色信息的专业表,例如销售代表或销售目标。每个表都有自己的id,每个表(查询表除外)都包含来自person表的id,该id被设置为外键。 (相信我很少有这样的东西,比如不必要的外键,反之则不然,错过FK,当你应该有一个是坏消息时。)
现在你仍然可以使用父表中的PK作为Fk到person表和专业表的PK,但我建议不要使用外键关系。无论如何,如果您没有在人员表中设置FK,那么您的数据注定会导致数据完整性问题。我更喜欢使用代理键,因此总是在每个表上设置我自己的键。从长远来看,它可以防止许多重新设计问题。如果要保持一对一的关系,就可以在该字段上使用简单的唯一索引。该表从一对一移动到一对多,您需要做的就是删除索引。如果你也使用它作为你的PK,那么你需要一个新的PK,所有引用pk的代码都必须改变。将新PK添加到包含150,000,000条记录的表中,而不是一项有趣的任务。