From 5781d27887c8077ce0b8203f94a2cde364bcf9ed Mon Sep 17 00:00:00 2001 From: David Ezzio Date: Fri, 7 Aug 2009 21:15:47 +0000 Subject: [PATCH] OpenJPA-235: merged fix from trunk 673258, "SQL reordering to avoid non-nullable foreign key constraint violations" git-svn-id: https://svn.apache.org/repos/asf/openjpa/branches/1.1.x@802195 13f79535-47bb-0310-9956-ffa450edef68 --- .../meta/strats/RelationFieldStrategy.java | 3 +- .../apache/openjpa/jdbc/sql/PrimaryRow.java | 11 ++-- .../apache/openjpa/jdbc/kernel/EntityF.java | 43 ++++++++++++++ .../apache/openjpa/jdbc/kernel/EntityG.java | 49 ++++++++++++++++ .../kernel/TestNoForeignKeyViolation.java | 56 ++++++++++++++++++- 5 files changed, 155 insertions(+), 7 deletions(-) create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/EntityF.java create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/EntityG.java diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/RelationFieldStrategy.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/RelationFieldStrategy.java index 143643128..dc43c73ad 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/RelationFieldStrategy.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/RelationFieldStrategy.java @@ -248,7 +248,8 @@ public class RelationFieldStrategy if (rel != null) { ForeignKey fk = field.getForeignKey((ClassMapping) rel.getMetaData()); - if (fk.getDeleteAction() == ForeignKey.ACTION_RESTRICT) { + if (fk.getDeleteAction() == ForeignKey.ACTION_RESTRICT || + fk.getDeleteAction() == ForeignKey.ACTION_CASCADE) { Row row = field.getRow(sm, store, rm, Row.ACTION_DELETE); row.setForeignKey(fk, null, rel); } diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/PrimaryRow.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/PrimaryRow.java index 183c3301b..3a0be1ba7 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/PrimaryRow.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/PrimaryRow.java @@ -192,10 +192,10 @@ public class PrimaryRow } /** - * If this is a delete, delay foreign keys to other deleted objects if - * the key is restricted. If this is an update or insert, delay foreign - * keys to other inserts if the key is not logical. If the foreign key - * is to a new record and the columns are auto-inc, record it. + * If this is a delete, delay foreign keys to other deleted objects if the + * key is restricted or cascade. If this is an update or insert, delay + * foreign keys to other inserts if the key is not logical. If the foreign + * key is to a new record and the columns are auto-inc, record it. */ private boolean delayForeignKey(ForeignKey fk, OpenJPAStateManager sm, boolean set) { @@ -204,7 +204,8 @@ public class PrimaryRow if (getAction() == ACTION_DELETE) return sm.isDeleted() && !fk.isDeferred() - && fk.getDeleteAction() == ForeignKey.ACTION_RESTRICT; + && (fk.getDeleteAction() == ForeignKey.ACTION_RESTRICT || + fk.getDeleteAction() == ForeignKey.ACTION_CASCADE); if (!sm.isNew() || sm.isFlushed()) return false; diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/EntityF.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/EntityF.java new file mode 100644 index 000000000..72d589f39 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/EntityF.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.openjpa.jdbc.kernel; +import java.util.List; + +import javax.persistence.*; + +@Entity +public class EntityF { + @Id private int id; + + @OneToMany(cascade=CascadeType.ALL, mappedBy="entityF") + private List listG; + + public List getListG() { + return listG; + } + public void setListG(List listG) { + this.listG = listG; + } + public int getId() { + return id; + } + public void setId(int id) { + this.id = id; + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/EntityG.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/EntityG.java new file mode 100644 index 000000000..c547dd086 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/EntityG.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.openjpa.jdbc.kernel; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.ManyToOne; + +import org.apache.openjpa.persistence.jdbc.ForeignKey; +import org.apache.openjpa.persistence.jdbc.ForeignKeyAction; + +@Entity +public class EntityG { + @Id private int id; + + @ForeignKey(deleteAction=ForeignKeyAction.CASCADE) + @ManyToOne (cascade=CascadeType.MERGE) + private EntityF entityF; + + public EntityF getEntityF() { + return entityF; + } + public void setEntityF(EntityF entityF) { + this.entityF = entityF; + } + public int getId() { + return id; + } + public void setId(int id) { + this.id = id; + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/TestNoForeignKeyViolation.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/TestNoForeignKeyViolation.java index 956e569e5..5dfc8c371 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/TestNoForeignKeyViolation.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/TestNoForeignKeyViolation.java @@ -18,6 +18,8 @@ */ package org.apache.openjpa.jdbc.kernel; +import java.util.ArrayList; +import java.util.List; import javax.persistence.EntityManager; import org.apache.openjpa.persistence.test.SingleEMFTestCase; @@ -37,7 +39,8 @@ public class TestNoForeignKeyViolation private EntityD entityD; public void setUp() { - setUp(EntityA.class, EntityB.class, EntityC.class, EntityD.class, EntityE.class); + setUp(EntityA.class, EntityB.class, EntityC.class, EntityD.class, + EntityE.class, EntityF.class, EntityG.class); createTestData(); } @@ -154,4 +157,55 @@ public class TestNoForeignKeyViolation em.close(); } } + + public void testForeignKeyCascade() { + EntityManager em = emf.createEntityManager(); + try { + EntityF f = new EntityF(); + f.setId(1); + + List listG = new ArrayList(); + EntityG g1 = new EntityG(); + g1.setId(1); + listG.add(g1); + g1.setEntityF(f); + + EntityG g2 = new EntityG(); + g2.setId(2); + listG.add(g2); + g2.setEntityF(f); + + EntityG g3 = new EntityG(); + g3.setId(3); + listG.add(g3); + g3.setEntityF(f); + + EntityG g4 = new EntityG(); + g4.setId(4); + listG.add(g4); + g4.setEntityF(f); + + f.setListG(listG); + em.getTransaction().begin(); + em.persist(f); + em.persist(g1); + em.persist(g2); + em.persist(g3); + em.persist(g4); + em.getTransaction().commit(); + + em.getTransaction().begin(); + em.remove(f); + em.getTransaction().commit(); + } + catch (Exception e) { + fail("Fail to delete EntityF"); + } + finally { + if (em.getTransaction().isActive()) + em.getTransaction().rollback(); + em.close(); + } + } + }