Мой вопрос касается каскадного удаления с помощью JPA и Eclipselink.
Я хотел бы смоделировать простую связь между двумя объектами: A и B. B ссылается на A через свойство ref2a (в терминах БД B.ref2a подключен к A.id через внешний ключ с параметром «ON DELETE CASCADE»). Моя цель - когда объект A удаляется, чтобы каскадировать удаление для всех объектов B, которые на него ссылаются.
Я много искал, но я не могу заставить его работать. Большинство решений, которые я нашел, предназначены для противоположной ситуации: A содержит набор ссылок на 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();
}
}
}