Ответ 1
Ваше сопоставление (упрощенное)
<?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);
Вы сказали, что он отлично работает , потому что у вас есть прикрепленный родительский экземпляр
Теперь посмотрим следующий (Notice 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 может быть отключена от базового JDBC-соединения после транзакции базы данных и повторно подключена при возникновении нового запроса клиента. Этот шаблон известен как сеанс для разговора и делает невозможным повторную привязку. Автоматическое управление версиями используется для изоляции одновременных изменений, и сеансу обычно не разрешается автоматически очищаться, но явно.
отказ от ответственности: у меня нет сценария, который использует длительный разговор. Java EE Stateful session beans поддерживает длительный разговор. Но его поддержка для JPA (не Hibernate)
Или вы можете создать альтернативное отображение, которое позволит вашему ребенку создавать составные элементы. Поскольку его жизненный цикл зависит от родительского объекта, вы можете полагаться на составные элементы, чтобы получить то, что вы хотите.
Создайте класс с именем AlternativeParent , который расширяет Parent
public class AlternativeParent extends Parent {}
Теперь его отображение (примечание Child как составной элемент вместо plain @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();
}
Я вижу зеленую полосу