Мой вопрос о каскадных удалениях с помощью JPA и Eclipselink.jpa cascading удаляет обратную связь
Я хотел бы, чтобы смоделировать простую связь между двумя сущностями: A и B. B ссылки А через свойство ref2a (в терминах DB 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(
[email protected](
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();
}
}
}
Привет, Крис, спасибо за ваш ответ. Я пробовал @CascadeOnDelete, но он не работает. Кстати, я хочу сделать противоположное тому, что вы описали. Я не хочу удалять ссылку. Я хочу удалить все ссылки FriendshipRelations, которые связаны с удаленным человеком через вторую ссылку (один на один обратный), а не через список «friendlyRelations». – mbax
Аннотации @CascadeOnDelete не удаляют дочерние строки для вас. Он просто сообщает JPA, что база данных удалит их. Если у вас не было настройки каскада delete в схеме DB, это не сработает. –
@mbax, проблема неясна, потому что вы включили OneToMany, которая не связана - попробуйте удалить ее из описания проблемы. Похоже, проблема заключается в том, что у вас есть одно сопоставление OneToOne, и вы хотите, чтобы сторона ссылки удалялась, когда удаленный человек был удален. Если это так, то вам нужно добавить отображение OneToOne от Person to FriendshipRelation, «отображаемое» в RelianceRelation.отношения человека, делая его двунаправленным отношением. В противном случае JPA не может узнать о экземпляре FriendshipRelation, который вы хотите удалить. Затем вы можете отметить это с помощью cascade.remove. – Chris