如何创建引用同一个表的多个复合外键约束?

时间:2013-07-23 20:25:05

标签: jpa eclipselink composite-primary-key

我正在使用EclipseLink 2.4.0,我正在尝试找到一种生成以下DDL语句的方法:

ALTER TABLE DELTA ADD CONSTRAINT DELTAFK1 FOREIGN KEY (APPKEY, NEWREVISION) REFERENCES REVISION (APPKEY, REVISION);
ALTER TABLE DELTA ADD CONSTRAINT DELTAFK2 FOREIGN KEY (APPKEY, OLDREVISION) REFERENCES REVISION (APPKEY, REVISION);

DELTA表中的每一行代表两个指定修订版之间的更改,主键由APPKEY,NEWREVISION和OLDREVISION组成。仅使用Delta.java类中定义的以下关系注释生成第一个alter语句:

public class Delta {

@EmbeddedId
private DeltaPK deltaPk;

@ManyToOne
@PrimaryKeyJoinColumns({
       @PrimaryKeyJoinColumn(name="appKey", referencedColumnName="appKey"),
       @PrimaryKeyJoinColumn(name="newRevision", referencedColumnName="revision")
})
private Revision newRevision;

@ManyToOne
@PrimaryKeyJoinColumns({
       @PrimaryKeyJoinColumn(name="appKey", referencedColumnName="appKey"),
       @PrimaryKeyJoinColumn(name="oldRevision", referencedColumnName="revision")
})
private Revision oldRevision;

每个PrimaryKeyJoinColumn,'appKey','oldRevision'和'newRevision'的名称值都是DeltaPK类中定义的字段,referencedColumnName值是Revision类中定义的字段。

我尝试了很多变种,而我最接近的就是当我为oldRevision对象注释掉'appKey'的PrimaryKeyJoinColumn时。然后生成第二个alter语句,但它只包含oldRevision值(不是appKey),正如您所期望的那样。如何实现这一点的任何想法或建议将不胜感激。

1 个答案:

答案 0 :(得分:0)

在我发现如何解决这个问题之前,我必须在调试器中查看EclipseLink源代码一段时间。事实证明,在我原来的问题中我没有提到问题的一个关键部分(因为我不知道这是问题的一部分)。 Revision类中的字段'appKey'和'revision'不是该表的主键,但它们构成了唯一性约束:

@Table(
    name = "REVISION",
    uniqueConstraints = @UniqueConstraint(columnNames = {"appKey", "revision"})
)

事实证明,EclipseLink部分地基于此唯一性约束中的columnNames的顺序生成外键约束的名称。这导致我的两个外键约束都使用相同的名称生成,这最终导致第二个被忽略而不生成。 (如果您想要汇总所有细节,请参阅org.eclipse.persistence.tools.schemaframework.TableDefinition中的以下方法。)

buildForeignKeyConstraint(List<String> fkFieldNames, List<String> pkFieldNames, TableDefinition targetTable, DatabasePlatform platform)
buildForeignKeyConstraintName(String tableName, String fieldName, int maximumNameLength, DatabasePlatform platform)
addForeignKeyConstraint(ForeignKeyConstraint foreignKey)

简而言之,当我简单地重新排序cloumnNames的值时,如:

@UniqueConstraint(columnNames = {"revision", "appKey"})

我有两个不同名称的外键约束(因为'revision'和'newRevison'和'oldRevision'之间有两个映射),如下所示:

ALTER TABLE DELTA ADD CONSTRAINT DELTA_NEWREVISION FOREIGN KEY (NEWREVISION, APPKEY) REFERENCES REVISION (REVISION, APPKEY)
ALTER TABLE DELTA ADD CONSTRAINT DELTA_OLDREVISION FOREIGN KEY (OLDREVISION, APPKEY) REFERENCES REVISION (REVISION, APPKEY)

对于不同的数据库平台(我使用的是Derby),您的输出可能略有不同,但我认为一般问题和解决方案是相同的。我希望我能够解释清楚,以便将来帮助其他人。