Su asignación (simplificado)
<?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>
produce
PARENT
ID
CHILD
CHILD_ID
PARENT_ID
Según lo que ha dicho
me gustaría ser capaz de tener Hibernate detectar que la colección infantil ha sido eliminado de el objeto primario, y tienen la filas de la tabla secundaria borrado de la base de datos cuando el objeto primario se actualiza
Algo así como
Parent parent = session.get(...);
parent.getChildren().clear();
session.update(parent);
Dijiste que funciona bien porque tiene una instancia principal adjunta
Ahora veamos el siguiente (Aviso Assert.assertNull (segundo))
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();
}
}
Desafortunadamente, la prueba no pasan. Lo que puedes hacer ???
- Habilitar una conversación de larga duración
referencia Hibernate dice
extendido (o largo) Sesión - La sesión de Hibernate puede ser desconectada de la conexión JDBC subyacente después de la transacción de base de datos tiene se ha confirmado y vuelto a conectar cuando se produce una nueva solicitud del cliente. Este patrón se conoce como sesión-por-conversación y hace que incluso la reinserción sea innecesaria. El control automático de versiones se utiliza para aislar modificaciones simultáneas y, por lo general, no se permite que la sesión se vacíe automáticamente, sino explícitamente.
descargo de responsabilidad: no tengo ningún escenario que utilice la conversación de larga ejecución. Los beans de sesión con estado de Java EE soportan conversaciones de larga ejecución. Pero su soporte es para JPA (no Hibernate)
O puede crear una asignación alternativa que habilite a su Niño como elementos compuestos.Debido a su ciclo de vida depende del objeto padre, puede depender de elementos compuestos para conseguir lo que quiere
Crear una clase llamada AlternativeParent que se extiende Padres
public class AlternativeParent extends Parent {}
Ahora su asignación (Aviso Niño como elemento compuesto en lugar de @Entity llanura)
<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>
Ahora implementar un cómodo es igual método en la clase del niño
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
}
}
Si i refactorizar el caso de prueba se muestra arriba (ahora mediante el uso de AlternativeParent lugar)
@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();
}
Veo una barra verde
Qué quiere decir, cargar la entidad existente y luego MERGE () 'con la instancia separada me pasó API? –
@ mattb: puede escribir una lógica para combinar la colección, o incluso simplemente reemplazar la colección anterior y establecer la nueva, pero asegúrese de haber agregado la etiqueta en su hbm. Este contendrá una consulta simple de eliminación de SQL para eliminar la colección completa antes de guardar una nueva. o de otra manera, donde quiera que agregue algo, esta eliminación sql se activará cada vez y luego se agregará una nueva copia de su colección. Esto puede resolver su problema de actualizar la colección de forma manual. –
No estoy seguro si me gusta esta solución, ya que requeriría cambiar mi patrón de uso, agregando '' por ejemplo. Esperaba que esto se pudiera arreglar con el mapeo solo. –