没有连接表的多对多映射

Posted

技术标签:

【中文标题】没有连接表的多对多映射【英文标题】:Many to Many mapping without join table 【发布时间】:2014-12-22 17:27:12 【问题描述】:

我有一个关于映射表的问题,我读过很多参考资料都说没有连接表很难进行多对多映射。

但是如果表 A 有一个来自表 B 的外键,反之亦然,例如 STUDENT 表有一个来自 CLASS 表的外键,它代表每个学生的班级“班级对学生一对多”,而 CLASS 表有来自 STUDENT 表的外键,表示属于“一对多班级的学生”的学生?

【问题讨论】:

【参考方案1】:

当您的STUDENT 表有CLASS 表的外键时,这意味着每个学生行最多可以对应一个班级行。反过来,这意味着当一个学生上不止一门课时,您必须为同一个学生输入多行。

同样,当您的CLASS 表有一个指向STUDENT 表的外键时,您的模型假定一个课程最多可以由一个学生参加,或者由CLASS 表中的多行表示.

如果同一项目有多行,则您的数据非规范化。这通常是一件坏事。虽然在某些情况下您无法避免它而不会对性能造成太大影响,但这绝对不是其中之一。

这就是为什么您需要一张桌子“介于”学生和班级之间。

【讨论】:

【参考方案2】:

如果您有一个正确规范化的数据库,那么您给出的示例将不起作用。只需考虑以下概念:

在您的学生表中,您应该有一个定义每个学生的主键。这意味着每个人只会有一行。您将有一个代表该类的列,但同样,如果您遵循正确的设计技术,该列应该只包含一个值。这意味着,您只能为每个学生安排一行,并且只能为他们分配一个班级。同样适用于类,你应该只有一行,即使你给它一个学生列,它也只能引用一个学生。

当然,你可以有一个糟糕的设计,允许多排学生,但它会为无数异常打开,并且保持前进会很糟糕。我强烈建议不要这样做。

我建议您创建一个交叉表,该表使用课程和学生参考的复合键。您的设计可能如下所示:

student:
| student_id | name | phone |

course:
| course_id | description | location |

enrollment:
| course_id | student_id |

编辑

如果您按照上述说明操作,您在 cmets 中提到的内容将不起作用。考虑这个不允许学生超过一行的学生表:

| student_name | class   |
+--------------+---------+
|    John      | Science |
|    Adam      | Math    |
|    Jane      | Science |

现在,没有什么能阻止我创建这样的类表:

| class   | student_name |
+---------+--------------+
| Science |    Joe       |
| Math    |    Jane      |

是的,所有信息都在那里。我知道 Adam 学数学,John 学科学,Joe 学科学,而 Jane 学数学和科学。

但是现在,如果亚当也想学科学怎么办?他不能,因为Science 已经有一行,Adam 已经有一行。如果更改其中任何一个,就会丢失一条信息。

【讨论】:

我可以通过在班级表的多行上使用相同的 student_FK 来为一个学生开设多个班级,并且我可以通过在学生表的多行上使用相同的 class_FK 来为一个班级开设多个学生。 虽然它可能在一定程度上起作用,但您会很快发现缺点。请查看我的编辑,@user3305603。

以上是关于没有连接表的多对多映射的主要内容,如果未能解决你的问题,请参考以下文章

推进:没有交叉表的多对多关系

多对多映射方法有啥区别

在休眠中的多对多映射中仅插入一个表

Hibernate的多对多关系

SSH高速进阶——Hibernate 多对多映射

没有集合的Hibernate中的多对多映射