2010-01-25 107 views
1

在做一些映射一对一关系的研究时,我遇到了一些让我质疑我的一些数据库设计决策的陈述。NHibnerate数据设计建议

基本上我有类似以下一些实体:

人联系,家长

两个触点和父母都是人。 一个人可能是联系人,父母,两者都不是。

我想出的数据库设计为这三个实体中的每一个都有一个表,并且所有三个表共享一个主ID(PersonID)。从数据库设计的角度来看,这似乎是一种很好的规范化和合理的表现方式来表示数据库及其关系(至少对我而言)。

此时,我开始编码C#类和NHibnerate映射来表示这些实体。我能找到的最自然的映射方法是使用映射。其他选项(一对一,一对多等)似乎要求我在表中添加一个或多个不必要的FK。在通过NHibernate的文档浏览我偶然发现了如下声明:

此功能常常对遗留数据模型有用,我们推荐比类和细粒度的领域模型表少。但是,如稍后所解释的,在单个层次结构中的继承映射策略之间进行切换非常有用。

我的问题是:

A)我是不是违反本校长? B)如果是这样,我会如何更好地设计这个系统?

这段陈述是否暗示我应该将所有Person/Contact/Parent字段合并到一个表中(带有许多可为空的字段)?或者我不知何故错过了这一点?

由于这是一个罕见的场合,我可以从头开始设计表格/类,所以我想说得对。先谢谢您的帮助!

编辑:我是如何打算的上述数据库设计更多信息工作:

的基本思路是,每个人得到的人表中的记录。相关表中记录的存在/不存在决定了这个人是否是家长,联系人等......这似乎强制执行一对多关系并允许快速查询/连接(共享主ID是在每个表中聚集PK)。

编辑:谢谢你们的帮助。当我设计这个系统时,我并没有真正考虑到查询能力,所以我将转向类似于Jamie Ide & hlgem建议的解决方案。我发现所有的答案有帮助。总而言之,共享主键看起来会导致c#端的对象模型出现一些问题。

回答

1

其中一些取决于您打算如何查询该数据。如果您想要轻松地查看某个人扮演角色的特定角色的角色,请制作角色表。要查看一个人的所有角色,无论您稍后添加了多少角色,只需要连接两个表。否则,你必须加入到每一个专业表(左联接,如果他们不存在),只是为了看看一个人有什么作用。表现不佳。

在我们的数据库中有很多这种类型的关系,我们有一个带有id的人员表,一个带有id和角色ID的角色表,以及一个查找角色的角色类型表。然后是具有特定角色信息的专业表,如销售代表或销售目标。每个表都有它自己的id,每个表(除查找表外)都包含来自person表的id,它被设置为外键。 (相信我很少有这样的事情,因为不必要的外键,反过来是不正确的,当你应该有一个坏消息时错过了FK。)

现在你仍然可以使用外键关系PK从父表中作为Fk到人表以及专业表的PK,但我建议不要这样做。无论如何,如果您没有为人员表设置FK,那么您的数据就注定会出现数据完整性问题。我更喜欢使用代理键,因此总是在每张桌子上设置自己的密钥。它从长远来看可以防止很多重新设计问题。如果你想保持一对一的关系,那么只需要一个简单的唯一索引就可以了。表格从一对一移动到一对多,你需要做的就是放弃索引。如果你也使用它作为你的PK,那么你需要一个新的PK,并且所有参考PK的代码都必须改变。将一个新的PK添加到一个包含150,000,000条记录的表中,而不是一项有趣的任务。

2

您的数据库设计需要一些工作;这是我的建议。

这很好,你有这样的想法,联系人和父母都可以是人;但是,您需要联系人和父母才能拥有不同的主键。您可以强制要求他们都具有Parent ID,并在Contact表和父表中引用Person表中的条目的Person ID并具有不可为空的外键。

所以Person表应该有一个唯一的主键(它的ID)和任何其他相关的列。联系人表应具有其自己的唯一主键(其ID),对Person表的不可空的外键引用(Person表中的ID)以及任何其他相关列。父表应具有其自己唯一的主键(其ID)以及对Person表(Person表中的ID)以及任何其他相关列的不可为空的外键引用。

这应该解决您的映射问题。如果您需要,您可以使用视图“重新组合”您的人员/家长/联系人“星座”(相关表格的集合)。

+0

谢谢你的建议。我同意这会解决我的映射问题。但是,我认为这使得数据库设计方面“更丑陋”。由于所有这些关系都应该是一对一的(也许我应该在第一篇文章中明确说明),您的建议似乎会在模型中引入大量不必要的FK。除此之外,它使关系成为一个>多个而不是一个>一个 - 最初的设计会强制执行正确的基数。 – Krazzy 2010-01-25 19:23:53

+0

@Krazzy:说实话,在不了解表格范围的情况下建议设计有点困难;因为我不知道Person,Parent和Contact有多少列,所以很难说出什么是好的设计。根据您的反馈,也许您最好将Parent和Contact表与Person表合并,并根据需要使用View来恢复父级和联系人? (这基本上是我原来的建议的反面...) – 2010-01-25 20:39:43

+0

@Krayzzy:无论如何,基本问题是共享主键。一个很好的通用规则(以及Hibernate广泛使用的规则)是为每个表都有一个不同的主键。 – 2010-01-25 20:41:04

1

你在问继承映射,而不是一对一的关系。您的设计需要table-per-subclass映射,但我不确定如何解决人员既可以是联系人又可以是父母的要求。我不知道一个好的方法来模拟这个,除了引入另一个涵盖两个角色的子类。这样想一下,如果您要求您的存储库返回一个人,并且该人既是联系人又是父级,那么应该返回哪种类型?

如果你坚持继承子类,那么我会建议坚持table-per-class如果可能的话。

但是更好的设计可能是引入一个“角色”表,并且在Person和Role之间具有一对多的关系。

编辑补充:恕我直言,你目前的设计将无法正常工作。什么类型的对象代表既是联系人又是父母的人?

您可以使用包含附加数据的“复杂”角色表来代替简单的角色表。您可以拥有一组角色对象(ContactRole,ParentRole等),每个对象都包含与该角色相关的字段。一个Person对象将有一个Role对象的集合。

+0

感谢您的建议。由于你提到的原因,继承不是一种选择。此外,将来可能会引入更多类型的“人员”,从而引入了一个子类来处理每个可能性很大的问题。一个简单的角色表不会工作,因为每个“角色”都需要该角色唯一的关联数据。 – Krazzy 2010-01-25 19:45:31

+0

@Krazzy:我编辑了我原来的答案,希望它有帮助。 – 2010-01-25 20:03:54

+0

再次感谢您的帮助 - 目的是在相关表格中存在/不存在记录将指示某个人是否属于给定类型。因此,对于既是联系人又是父母的人员,个人,联系人和家长的记录将出现在相应的表格中。 – Krazzy 2010-01-25 20:15:03