复合键的复合键

时间:2012-05-18 11:17:59

标签: java mysql sql hibernate jpa

我正在尝试了解我正在创建的数据模型采取的方法。我有两个表,我最初使用复合键创建。我现在正在添加第3个表,它是前两个的连接表,这将导致三个字段和两个外键的复合键,每个字段包含2个字段。这可能是在MySQL中,并与某种Java持久性框架一起使用。我一直都喜欢使用复合键,因为它似乎是一种更自然的方式来表示数据,但我想确保自己不会为以后的世界做好准备。我应该继续使用上面提到的方法还是只在表上创建一些自动递增的ID?

3 个答案:

答案 0 :(得分:2)

如果你的多对多是纯粹的关系(没有自己的属性)并且永远不会被引用,那么只需使用复合键。

如果它可能有自己的属性或被引用(如实例化为类),您可能想要一个代理键,因为许多ORM需要id是一个整数。

答案 1 :(得分:2)

Hibernate建议使用纯技术的,自动生成的非复合键(纯连接表除外)。而且有很好的理由,IMO。

使用复合键,您的映射会更加困难。由于更复杂的指数,表现将会降低。一般编程会更难,因为不是能够识别只有很长的给定实体,你需要两个或三个长(想想URL和表格,例如,你必须放置两个或三个参数/隐藏字段到您的网址/表单。)

当然,如果密钥是有用的,那就更糟了,因为你必须在某个时候更改主密钥的一个部分,这将迫使你更新对这个主密钥的所有引用。

答案 2 :(得分:2)

在限制与外键的更深层关系时,连接表的代理键有一个巨大缺点。我们需要一个6桌的设置来演示它。

基表:

CREATE TABLE semester (semester_id INTEGER PRIMARY KEY, semester_name VARCHAR(40));
CREATE TABLE student  (student_id  INTEGER PRIMARY KEY, student_name  VARCHAR(40));
CREATE TABLE subject  (subject_id  INTEGER PRIMARY KEY, subject_name  VARCHAR(40));

然后让我们连接它们:

CREATE TABLE enrollment (
  enrollment_id INTEGER PRIMARY KEY,
  semester_id INTEGER NOT NULL,
  student_id INTEGER NOT NULL,
  room_number INTEGER,
  FOREIGN KEY (semester_id) REFERENCES semester (semester_id),
  FOREIGN KEY (student_id)  REFERENCES student  (student_id),
  UNIQUE INDEX (semester_id, student_id)
);

-- similarly ...
CREATE TABLE class(class_id ..., semester_id ..., subject_id ..., class_number ...);

到目前为止,一切都很棒。但是,我们需要将它们连接起来:

CREATE TABLE grades (
  student_in_class_id INTEGER PRIMARY KEY,
  enrollment_id INTEGER NOT NULL,
  class_id INTEGER NOT NULL,
  grade char(1),
  FOREIGN KEY enrollment (enrollment_id),
  FOREIGN KEY class (class_id),
  UNIQUE INDEX (enrollment_id, class_id)
);

问题: 我们应该如何强制执行注册和课程同时参考同一学期?(简答:我们可以't

与复合键相同 - 这里我不需要额外的键来强制FOREIGN KEY的UNIQUE组合,PRIMARY KEY默认为我做这个:

CREATE TABLE enrollment (
  semester_id INTEGER NOT NULL,
  student_id INTEGER NOT NULL,
  room_number INTEGER,
  PRIMARY KEY (semester_id, student_id),
  FOREIGN KEY (semester_id) REFERENCES semester (semester_id),
  FOREIGN KEY (student_id)  REFERENCES student  (student_id)
);

-- along the same lines...
class(semester_id ..., subject_id ..., class_number ...)

然后是不祥的成绩表:

CREATE TABLE grades (
  semester_id INTEGER NOT NULL,
  student_id INTEGER NOT NULL,
  subject_id INTEGER NOT NULL,
  PRIMARY KEY (semester_id, student_id, subject_id),
  FOREIGN KEY (semester_id, student_id) REFERENCES enrollment(semester_id, student_id),
  FOREIGN KEY (semester_id, subject_id) REFERENCES class(semester_id, subject_id)
);

这样,我的关系正确表达约束。

额外奖励:我可以使用简单联接获取semester_namestudent_namesubject_name值(而不必通过多个级别遍历架构)。 )你可能会拥有比这个最简单的例子更多的等级,然后更加明显的是回到任何父关系是多么容易。

更改架构更复杂,但即使它是:是不是关于建模数据的数据建模?我们是否可以因为我们崇拜代理键而抛弃参照完整性?

注意: Hibernate 处理复合键。 DataMapper for Ruby也是如此。