Ваше отображение (упрощенное)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="br.com._3988215.model.domain">
<class name="Parent" table="PARENT">
<id name="id">
<generator class="native"/>
</id>
<bag cascade="all,delete-orphan" name="childList">
<key column="PARENT_ID" not-null="false"/>
<one-to-many class="Child"/>
</bag>
</class>
<class name="Child" table="CHILD">
<id name="id" column="CHILD_ID">
<generator class="native"/>
</id>
</class>
</hibernate-mapping>
производит
PARENT
ID
CHILD
CHILD_ID
PARENT_ID
Согласно тому, что вы сказали
Я бы хотел, чтобы Hibernate обнаружил, что дочерняя коллекция была удалена из родительского объекта, и удалил строки в дочерней таблице из базы данных при обновлении родительского объекта
что-то вроде
Parent parent = session.get(...);
parent.getChildren().clear();
session.update(parent);
Вы сказали, что он работает нормально , потому что у вас есть прикрепленный родительский экземпляр
Теперь давайте посмотрим на следующее (Обратите внимание Assert.assertNull (секунда) )
public class WhatYouWantTest {
private static SessionFactory sessionFactory;
private Serializable parentId;
private Serializable firstId;
private Serializable secondId;
@BeforeClass
public static void setUpClass() {
Configuration c = new Configuration();
c.addResource("mapping.hbm.3988215.xml");
sessionFactory = c.configure().buildSessionFactory();
}
@Before
public void setUp() throws Exception {
Parent parent = new Parent();
Child first = new Child();
Child second = new Child();
Session session = sessionFactory.openSession();
session.beginTransaction();
parentId = session.save(parent);
firstId = session.save(first);
secondId = session.save(second);
parent.getChildList().add(first);
parent.getChildList().add(second);
session.getTransaction().commit();
session.close();
}
@Test
public void removed_second_from_parent_remove_second_from_database() {
Parent parent = new Parent();
parent.setId((Integer) parentId);
Child first = new Child();
first.setId((Integer) firstId);
/**
* It simulates the second one has been removed
*/
parent.getChildList().add(first);
Session session = sessionFactory.openSession();
session.beginTransaction();
session.update(parent);
session.getTransaction().commit();
session.close();
session = sessionFactory.openSession();
session.beginTransaction();
Child second = (Child) session.get(Child.class, secondId);
Assert.assertNull(second);
session.getTransaction().commit();
session.close();
}
}
К сожалению , тест не пройден. Что вы можете сделать ???
- Включить длительный разговор
Hibernate ссылка говорит
Расширенный (или длинный) сеанс - сеанс Hibernate может быть отключен от базового соединения JDBC после фиксации транзакции базы данных и переподключен, когда происходит новый запрос клиента. Этот шаблон известен как сеанс на разговор и делает ненужным даже присоединение . Автоматическое управление версиями используется для изоляции одновременных изменений, и сеанс обычно не может быть сброшен автоматически, но явно.
Disclaimer: у меня нет сценария, который использует длительный разговор. Java EE Stateful сессионные компоненты поддерживают длительный диалог. Но его поддержка для JPA (не Hibernate)
Или вы можете создать альтернативное отображение, которое позволит вашему Ребёнку составным элементам. Поскольку его жизненный цикл зависит от родительского объекта, вы можете полагаться на составные элементы, чтобы получить то, что вы хотите
Создайте класс с именем AlternativeParent , который расширяет Parent
public class AlternativeParent extends Parent {}
Теперь его отображение (обратите внимание на Child как составной элемент вместо простого @Entity)
<class name="AlternativeParent" table="PARENT">
<id name="id">
<generator class="native"/>
</id>
<bag name="childList" table="CHILD">
<key column="PARENT_ID" not-null="false"/>
<composite-element class="Child">
<property column="CHILD_ID" name="id"/>
</composite-element>
</bag>
</class>
Теперь реализуйте удобный метод equals в классе Child
public boolean equals(Object o) {
if (!(o instanceof Child))
return false;
Child other = (Child) o;
// identity equality
// Used by composite elements
if(getId() != null) {
return new EqualsBuilder()
.append(getId(), other.getId())
.isEquals();
} else {
// object equality
}
}
Если я рефакторинг тестового примера, показанного выше (теперь с использованием AlternativeParent вместо)
@Test
public void removed_second_from_parent_remove_second_from_database() {
AlternativeParent parent = new AlternativeParent();
parent.setId((Integer) parentId);
Child first = new Child();
first.setId((Integer) firstId);
/**
* It simulates the second one has been removed
*/
parent.getChildList().add(first);
Session session = sessionFactory.openSession();
session.beginTransaction();
session.update(parent);
session.getTransaction().commit();
session.close();
session = sessionFactory.openSession();
session.beginTransaction();
Child second = (Child) session.get(Child.class, secondId);
Assert.assertNull(second);
session.getTransaction().commit();
session.close();
}
Я вижу зеленую полосу