我的问题是关于使用JPA和Eclipselink级联删除。
我想模拟两个实体之间的简单关系:A和B. B通过属性引用A ref2a (在数据库术语 B.ref2a 中连接到 A.id 通过带有“ON DELETE CASCADE”的外键)。 我的目标是删除A对象以将删除级联到引用它的所有B对象。
我搜索了很多,但我无法使其发挥作用。我发现的大多数解决方案都是针对相反的情况:A包含对B的引用集合。这就像一个魅力。但如果引用是在B方面,我不知道该怎么做。
以下是代码示例:
@Entity
public class A
{
@Id
@GeneratedValue
private Integer id;
private String name;
// ...
}
@Entity
public class B
{
@Id
@GeneratedValue
private Integer id;
private String name;
@OneToOne
@JoinColumn(
foreignKey=@ForeignKey(
foreignKeyDefinition="FOREIGN KEY ref2a REFERENCES A id ON DELETE CASCADE"
)
)
private A ref2a;
// ...
}
测试代码:
public class CascadeTest extends TestCase
{
private EntityManagerFactory emf;
private EntityManager em;
@Override
protected void setUp() throws Exception {
emf = Persistence.createEntityManagerFactory("myDB");
em = emf.createEntityManager();
}
@Override
protected void tearDown() throws Exception {
em.close();
emf.close();
}
public void testApp()
{
Integer aid = -1, bid = -1;
try {
em.getTransaction().begin();
A a = new A();
a.setName("My name is A");
B b = new B();
b.setRef2a(a);
b.setName("My name is B, please delete me when A is gone.");
em.persist(a);
em.persist(b);
em.getTransaction().commit();
aid = a.getId();
bid = b.getId();
} finally {
if (em.getTransaction().isActive())
em.getTransaction().rollback();
}
try {
em.getTransaction().begin();
B b = em.find(B.class, bid);
assertNotNull(b);
assertEquals("My name is B, please delete me when A is gone.", b.getName());
assertEquals("My name is A", b.getRef2a().getName());
assertEquals(aid, b.getRef2a().getId());
A a = em.find(A.class, aid);
assertEquals("My name is A", a.getName());
em.remove(a);
em.getTransaction().commit();
em.getTransaction().begin();
// a should have been removed.
// This passes OK.
a = em.find(A.class, aid);
assertNull(a);
// Cascading deletes should have deleted also b.
b = em.find(B.class, bid);
// PROBLEM: This fails - b is still here.
assertNull(b);
em.getTransaction().commit();
} finally {
if (em.getTransaction().isActive())
em.getTransaction().rollback();
}
}
}
答案 0 :(得分:1)
我已经解决了我的问题。真的很简单 - 我的初始代码几乎是正确的。我只是在外键级联中遇到了语法问题。需要在括号“()”中的属性,我在文档中忽略了这一点。 所以我需要做的改变是:
@OneToOne
@JoinColumn(
foreignKey=@ForeignKey(
foreignKeyDefinition="FOREIGN KEY (ref2a) REFERENCES A (id) ON DELETE CASCADE"
)
)
private A ref2a;
请注意两个属性的括号。
这样做,删除A对象也会级联其链接的B对象。
感谢大家的帮助!
答案 1 :(得分:-1)
EclipseLink提供了一个与数据库" ON DELETE CASCADE"对齐的@CascadeOnDelete注释。 contraint。此注释告诉EclipseLink,当删除此实体时,实体将被数据库foriegn键约束删除,如果使用DDL,EclipseLink将生成具有适当约束的表。 有关详细信息,请参阅https://wiki.eclipse.org/EclipseLink/Examples/JPA/DeleteCascade。
我认为你可以在FriendshipRelation.person映射上使用简单的级联删除:
@Entity
public class FriendshipRelation {
..
@OneToOne(cascade=CascadeType.REMOVE)
private Person person;
这将强制JPA在删除FriendshipRelation实例时删除任何被引用的人。