有人可以解释为什么我没有看到OpenJPA的@ForeignKey注释要求Cascade Delete的预期结果吗?
我已将此缩减为一个小型测试用例,其中包含两个JPA实体类" Parent"和"孩子"分别由OneToMany和ManyToOne关系相关。 Child与Parent的关系使用OpenJPA @ForeignKey注释进行注释,指定删除应该级联。
映射和SchemaFactory设置设置为尊重外键。
数据库正确反映了外键关系。
但是,在测试用例中,当我删除父级时,子级不会删除。
的persistence.xml:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- See this: http://forum.springsource.org/showthread.php?58527-transaction-type-quot-JTA-quot-quot-RESOURCE_LOCAL-quot -->
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="entitiesTestPersistenceUnit" transaction-type="JTA">
<provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
<jta-data-source>entitiesDsJtaTest</jta-data-source>
<non-jta-data-source>entitiesDsNonJtaTest</non-jta-data-source>
<validation-mode>AUTO</validation-mode>
<properties>
<property name="openjpa.jdbc.DBDictionary" value="org.apache.openjpa.jdbc.sql.PostgresDictionary"/>
<property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)" />
<property name="openjpa.jdbc.SchemaFactory" value="native(ForeignKeys=true)"/>
<property name="openjpa.RuntimeUnenhancedClasses" value="unsupported" />
<property name="openjpa.Log" value="slf4j" />
<property name="openjpa.LockTimeout" value="5000" />
</properties>
</persistence-unit>
</persistence>
父类:
@Entity
public class Parent extends DbEntity {
public Parent() {
}
private String name;
public void setName (String name) {
this.name = name;
}
public String getName() {
return this.name;
}
@OneToMany(mappedBy = "parent", fetch=FetchType.LAZY)
private Set<Child> children = new HashSet<>();
public void addChild(Child child) {
if (child.getParent() != this) {
throw new IllegalStateException(
"Attempt to add a Child to a usage point that does not own it.");
}
this.getChildren().add(child);
}
public void removeChild(Child child) {
if (child.getParent() != null) {
throw new IllegalStateException(
"Attempt to remove a Child that stil belongs to a Parent.");
}
this.children.remove(child);
}
public boolean hasChild(Child child) {
return this.children.contains(child);
}
public Set<Child> getChildren() {
return this.children;
}
}
儿童班:
@Entity
public class Child extends DbEntity {
public Child() {
}
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
@ManyToOne(fetch=FetchType.LAZY)
@ForeignKey(deleteAction = ForeignKeyAction.CASCADE, updateAction = ForeignKeyAction.CASCADE)
private Parent parent = null;
public Parent getParent() {
return this.parent;
}
public void setParent(Parent parent) {
Parent old = this.getParent();
if (parent != old) {
if (old != null) {
this.parent = null;
old.removeChild(this);
}
this.parent = parent;
if (parent != null) {
parent.addChild(this);
}
}
}
}
测试用例(用Arquillian运行)
@Test
public void testCascadeDeleteParent() throws IllegalStateException, SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException, SystemException, NotSupportedException {
Child child = new Child();
em.persist(child);
Parent parent = new Parent();
em.persist(parent);
child.setParent(parent);
long id1 = child.getId();
// Child is manaaged.
Assert.assertNotNull("child has no ID?", id1);
long id2 = parent.getId();
Assert.assertNotNull("parent has no ID?", id2);
this.em.remove(parent);
Parent p2 = this.em.find(Parent.class, id2);
Assert.assertNull("Parent should be gone; we deleted it. ", p2);
Child s1 = this.em.find(Child.class, id1);
Assert.assertNull("Child should be gone after Parent is deleted.", s1);
}
数据库肯定有外键操作:
test=# \d+ dbentity;
Table "public.dbentity"
Column | Type | Modifiers | Storage | Stats target | Description
-----------+------------------------+-----------+----------+--------------+-------------
id | bigint | not null | plain | |
version | integer | | plain | |
dtype | character varying(255) | | extended | |
name | character varying(255) | | extended | |
parent_id | bigint | | plain | |
Indexes:
"dbentity_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
"dbentity_parent_id_fkey" FOREIGN KEY (parent_id) REFERENCES dbentity(id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE
Referenced by:
TABLE "dbentity" CONSTRAINT "dbentity_parent_id_fkey" FOREIGN KEY (parent_id) REFERENCES dbentity(id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE
Has OIDs: no
test=#
堆栈顶部的跟踪,无论它的价值如何:
java.lang.AssertionError: Child should be gone after Parent is deleted. expected null, but was:<com.testco.Child@5bfcf845>
at org.junit.Assert.fail(Assert.java:88)
at org.junit.Assert.failNotNull(Assert.java:664)
at org.junit.Assert.assertNull(Assert.java:646)
at com.testco.ChildIntegrationTest.testCascadeDeleteParent(ChildIntegrationTest.java:138)