Bug 441546 - Foreign Key attribute when used in JoinColumn generates wrong DDL statement.
- Added unit test to ForeignKeyTestSuite.
- Reviewed By Lukas Jungmann <lukas.jungmann@oracle.com>
diff --git a/jpa/eclipselink.jpa.test/resource/eclipselink-jpa21-model/persistence.xml b/jpa/eclipselink.jpa.test/resource/eclipselink-jpa21-model/persistence.xml
index de12e0c..792b0c0 100644
--- a/jpa/eclipselink.jpa.test/resource/eclipselink-jpa21-model/persistence.xml
+++ b/jpa/eclipselink.jpa.test/resource/eclipselink-jpa21-model/persistence.xml
@@ -73,6 +73,8 @@
<class>org.eclipse.persistence.testing.models.jpa21.advanced.ddl.Athlete</class>
<class>org.eclipse.persistence.testing.models.jpa21.advanced.ddl.Race</class>
<class>org.eclipse.persistence.testing.models.jpa21.advanced.ddl.Coach</class>
+ <class>org.eclipse.persistence.testing.models.jpa21.advanced.ddl.Driver</class>
+ <class>org.eclipse.persistence.testing.models.jpa21.advanced.ddl.Vehicle</class>
<class>org.eclipse.persistence.testing.models.jpa21.advanced.converters.AccomplishmentConverter</class>
<class>org.eclipse.persistence.testing.models.jpa21.advanced.converters.AgeConverter</class>
<class>org.eclipse.persistence.testing.models.jpa21.advanced.converters.DateConverter</class>
diff --git a/jpa/eclipselink.jpa.test/resource/eclipselink-jpa21-model/server/persistence.xml b/jpa/eclipselink.jpa.test/resource/eclipselink-jpa21-model/server/persistence.xml
index f36593b..c194388 100644
--- a/jpa/eclipselink.jpa.test/resource/eclipselink-jpa21-model/server/persistence.xml
+++ b/jpa/eclipselink.jpa.test/resource/eclipselink-jpa21-model/server/persistence.xml
@@ -80,6 +80,8 @@
<class>org.eclipse.persistence.testing.models.jpa21.advanced.ddl.Athlete</class>
<class>org.eclipse.persistence.testing.models.jpa21.advanced.ddl.Race</class>
<class>org.eclipse.persistence.testing.models.jpa21.advanced.ddl.Coach</class>
+ <class>org.eclipse.persistence.testing.models.jpa21.advanced.ddl.Driver</class>
+ <class>org.eclipse.persistence.testing.models.jpa21.advanced.ddl.Vehicle</class>
<class>org.eclipse.persistence.testing.models.jpa21.advanced.converters.AccomplishmentConverter</class>
<class>org.eclipse.persistence.testing.models.jpa21.advanced.converters.AgeConverter</class>
<class>org.eclipse.persistence.testing.models.jpa21.advanced.converters.DateConverter</class>
diff --git a/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa21/advanced/ddl/Driver.java b/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa21/advanced/ddl/Driver.java
new file mode 100644
index 0000000..ae7cc0a
--- /dev/null
+++ b/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa21/advanced/ddl/Driver.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * 07/07/2017-2.7 Vikram Bhatia
+ * - 441546: Foreign Key attribute when used in JoinColumn generates wrong DDL statement
+ ******************************************************************************/
+package org.eclipse.persistence.testing.models.jpa21.advanced.ddl;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "JPA21_DDL_DRIVER")
+public class Driver {
+ @Id
+ @Column(name = "NAME")
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+}
diff --git a/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa21/advanced/ddl/Vehicle.java b/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa21/advanced/ddl/Vehicle.java
new file mode 100644
index 0000000..c5498ff
--- /dev/null
+++ b/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa21/advanced/ddl/Vehicle.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * 07/07/2017-2.7 Vikram Bhatia
+ * - 441546: Foreign Key attribute when used in JoinColumn generates wrong DDL statement
+ ******************************************************************************/
+package org.eclipse.persistence.testing.models.jpa21.advanced.ddl;
+
+import javax.persistence.Entity;
+import javax.persistence.ForeignKey;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+
+@Entity
+@Table(name="JPA21_DDL_VEHICLE")
+public class Vehicle {
+
+ @Id
+ private String vnum;
+
+ @ManyToOne
+ @JoinColumn(name="LAST",foreignKey=@ForeignKey(name="FKv2d"))
+ private Driver driver;
+
+ public String getVnum() {
+ return vnum;
+ }
+ public void setVnum(String vnum) {
+ this.vnum = vnum;
+ }
+ public Driver getDriver() {
+ return driver;
+ }
+ public void setDriver(Driver driver) {
+ this.driver = driver;
+ }
+}
diff --git a/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/tests/jpa21/advanced/ForeignKeyTestSuite.java b/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/tests/jpa21/advanced/ForeignKeyTestSuite.java
index dcb2677..9e7697d 100644
--- a/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/tests/jpa21/advanced/ForeignKeyTestSuite.java
+++ b/jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/tests/jpa21/advanced/ForeignKeyTestSuite.java
@@ -27,6 +27,7 @@
import javax.persistence.EntityManager;
import org.eclipse.persistence.descriptors.ClassDescriptor;
+import org.eclipse.persistence.exceptions.DatabaseException;
import org.eclipse.persistence.internal.helper.DatabaseTable;
import org.eclipse.persistence.internal.queries.MappedKeyMapContainerPolicy;
import org.eclipse.persistence.mappings.DirectCollectionMapping;
@@ -41,6 +42,7 @@
import org.eclipse.persistence.testing.framework.junit.JUnitTestCase;
import org.eclipse.persistence.testing.models.jpa21.advanced.ddl.Coach;
+import org.eclipse.persistence.testing.models.jpa21.advanced.ddl.Driver;
import org.eclipse.persistence.testing.models.jpa21.advanced.ddl.Organizer;
import org.eclipse.persistence.testing.models.jpa21.advanced.ddl.Race;
import org.eclipse.persistence.testing.models.jpa21.advanced.ddl.Responsibility;
@@ -49,7 +51,7 @@
import org.eclipse.persistence.testing.models.jpa21.advanced.ddl.RunnerStatus;
import org.eclipse.persistence.testing.models.jpa21.advanced.ddl.Shoe;
import org.eclipse.persistence.testing.models.jpa21.advanced.ddl.Sprinter;
-
+import org.eclipse.persistence.testing.models.jpa21.advanced.ddl.Vehicle;
import org.eclipse.persistence.testing.models.jpa21.advanced.enums.Health;
import org.eclipse.persistence.testing.models.jpa21.advanced.enums.Level;
import org.eclipse.persistence.testing.models.jpa21.advanced.enums.RunningStatus;
@@ -95,6 +97,7 @@ public static Test suite() {
suite.addTest(new ForeignKeyTestSuite("testElementCollectionForeignKeys"));
suite.addTest(new ForeignKeyTestSuite("testReadAndWriteDDLObjects"));
+ suite.addTest(new ForeignKeyTestSuite("testBug441546"));
return suite;
@@ -268,4 +271,63 @@ public void testReadAndWriteDDLObjects() {
closeEntityManager(em);
}
}
+
+ /**
+ * Tests a many to one foreign key setting with null foreign key definition.
+ */
+ public void testBug441546() {
+ EntityManager em = createEntityManager();
+
+ try {
+ beginTransaction(em);
+
+ Driver driver = new Driver();
+ driver.setName("Bob");
+
+ Vehicle vehicle = new Vehicle();
+ vehicle.setVnum("1A467");
+ vehicle.setDriver(driver);
+
+ em.persist(driver);
+ em.persist(vehicle);
+ commitTransaction(em);
+
+ } catch (RuntimeException e) {
+ if (isTransactionActive(em)){
+ rollbackTransaction(em);
+ }
+
+ throw e;
+ } finally {
+ closeEntityManager(em);
+ }
+
+ em = createEntityManager();
+ try {
+ // Try Deleting Driver with constraint
+ beginTransaction(em);
+
+ Driver d2 = em.find(Driver.class, "Bob");
+ em.remove(d2);
+
+ commitTransaction(em);
+ fail("Foreign Key constraint is not defined in database on table.");
+
+ } catch (RuntimeException e) {
+ if (isTransactionActive(em)){
+ rollbackTransaction(em);
+ }
+
+ Throwable cause = e.getCause();
+
+ if (cause instanceof DatabaseException) {
+ assertTrue("Error Deleting row with constraint with different error.", cause.getCause() instanceof java.sql.SQLIntegrityConstraintViolationException);
+ } else {
+ throw e;
+ }
+
+ } finally {
+ closeEntityManager(em);
+ }
+ }
}
diff --git a/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/metadata/accessors/mappings/MappingAccessor.java b/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/metadata/accessors/mappings/MappingAccessor.java
index 1e20113..f9d2268 100644
--- a/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/metadata/accessors/mappings/MappingAccessor.java
+++ b/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/metadata/accessors/mappings/MappingAccessor.java
@@ -103,6 +103,7 @@
import static org.eclipse.persistence.internal.jpa.metadata.MetadataConstants.JPA_CONVERTS;
import static org.eclipse.persistence.internal.jpa.metadata.MetadataConstants.JPA_FETCH_EAGER;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
@@ -1886,7 +1887,10 @@ protected void processForeignKeyRelationship(ForeignReferenceMapping mapping, Li
// join, or if we simply set the whole mapping as read-only
boolean allReadOnly = true;
Map<DatabaseField, DatabaseField> fields = new HashMap<DatabaseField, DatabaseField>();
-
+ List<String> sourceFields = new ArrayList<String>();
+ List<String> targetFields = new ArrayList<String>();
+ String targetTableName = null;
+
// Build our fk->pk associations.
for (JoinColumnMetadata joinColumn : joinColumns) {
// Look up the primary key field from the referenced column name.
@@ -1904,6 +1908,11 @@ protected void processForeignKeyRelationship(ForeignReferenceMapping mapping, Li
}
fields.put(fkField, pkField);
+ sourceFields.add(fkField.getName());
+ targetFields.add(pkField.getName());
+ if (targetTableName == null) {
+ targetTableName = pkField.getTableName();
+ }
allReadOnly = allReadOnly && fkField.isReadOnly();
}
@@ -1938,7 +1947,7 @@ protected void processForeignKeyRelationship(ForeignReferenceMapping mapping, Li
// the spec case (on the source table) and our extended support when
// the fk's are on the target table as well.
if (foreignKey != null) {
- foreignKey.process(foreignKeyTable);
+ foreignKey.process(foreignKeyTable, sourceFields, targetFields, targetTableName);
}
}
diff --git a/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/metadata/columns/ForeignKeyMetadata.java b/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/metadata/columns/ForeignKeyMetadata.java
index cb47276..0df4770 100644
--- a/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/metadata/columns/ForeignKeyMetadata.java
+++ b/jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/metadata/columns/ForeignKeyMetadata.java
@@ -17,6 +17,8 @@
******************************************************************************/
package org.eclipse.persistence.internal.jpa.metadata.columns;
+import java.util.List;
+
import org.eclipse.persistence.internal.helper.DatabaseTable;
import org.eclipse.persistence.internal.jpa.metadata.MetadataConstants;
import org.eclipse.persistence.internal.jpa.metadata.ORMetadata;
@@ -164,11 +166,34 @@ protected boolean isProviderDefaultConstraintMode() {
* Process this JPA metadata into an EclipseLink ForeignKeyConstraint.
*/
public void process(DatabaseTable table) {
+ process(table, null, null, null);
+ }
+
+ /**
+ * INTERNAL:
+ * Process this JPA metadata into an EclipseLink ForeignKeyConstraint.
+ */
+ public void process(DatabaseTable table, List<String> sourceFields, List<String> targetFields, String targetTableName) {
if (! isProviderDefaultConstraintMode()) {
ForeignKeyConstraint foreignKeyConstraint = new ForeignKeyConstraint();
foreignKeyConstraint.setName(getName());
foreignKeyConstraint.setForeignKeyDefinition(getForeignKeyDefinition());
foreignKeyConstraint.setDisableForeignKey(isNoConstraintMode());
+ // Bug 441546 - Foreign Key attribute when used in JoinColumn generates wrong DDL statement
+ // If foreignKeyDefinition element is not specified, the provider will generate foreign
+ // key constraints whose update and delete actions it determines most appropriate for
+ // the join column(s) to which the foreign key annotation is applied.
+ if (getForeignKeyDefinition() == null) {
+ if (sourceFields != null) {
+ foreignKeyConstraint.setSourceFields(sourceFields);
+ }
+ if (targetFields != null) {
+ foreignKeyConstraint.setTargetFields(targetFields);
+ }
+ if (targetTableName != null) {
+ foreignKeyConstraint.setTargetTable(targetTableName);
+ }
+ }
table.addForeignKeyConstraint(foreignKeyConstraint);
}
}