2010-07-21 13 views
12
@Entity 
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) 
@Table(name = "company_policies") 
@DiscriminatorColumn(name = "rule_name") 
public abstract class AbstractPolicyRule implements Serializable { 

    @Transient 
    private static final long serialVersionUID = 1L; 

    @Id 
    @GeneratedValue 
    private Long id; 
    private String value; 

    ... 
} 

_huérfanos permanecen en la base de datos incluso con orphanRemoval = true en uno-a-muchos relación (JPA/Hibernate)

@Entity 
public class Category implements Serializable { 

    @Transient 
    private static final long serialVersionUID = 1L; 

    @Id 
    @GeneratedValue 
    private Long id; 
    @Column(name = "category_name") 
    private String name; 

    @OneToMany(fetch = FetchType.EAGER, cascade = { CascadeType.ALL }, orphanRemoval = true) 
    @JoinColumn(name = "category_policy_id", referencedColumnName = "id") 
    private Set<AbstractPolicyRule> activePolicyRules; 

    ... 
} 

Cuando este conjunto se actualiza los activePolicyRules existentes han puesto su category_policy_id en nulo en la base de datos y las nuevas están insertadas Me gustaría que los originales sean eliminados.

Pensé que agregar orphanRemoval = true haría eso pero no es así. Otras preguntas que he visto sobre esto parecen tener relaciones bidireccionales y establecer el padre en nulo lo resuelve, pero esta no es una relación bidireccional.

¿Alguna sugerencia?

usando Hibernate 3.5.3

Editar: Esto sólo ocurre cuando existe una AbstractPolicyRule existente en la base de datos, se quita de la lista y luego salvar la categoría de nuevo. Su clave externa, category_policy_id, se establece en nulo en lugar de eliminarse.

[DEBUG] Collection found: [domain.category.Category.activePolicyRules#1], was: 
[<unreferenced>] (initialized) 
[DEBUG] Flushed: 0 insertions, 2 updates, 0 deletions to 2 objects 
[DEBUG] Flushed: 1 (re)creations, 0 updates, 1 removals to 1 collections 
... 
[DEBUG] Deleting collection: [domain.category.Category2.activePolicyRules#1] 
[DEBUG] about to open PreparedStatement (open PreparedStatements: 0, globally: 0) 
[DEBUG] update company_policies set category_policy_id=null where category_policy_id=? 
[DEBUG] done deleting collection 

También probamos un, porque la documentación de Hibernate desalienta la forma anterior:

@Entity 
public class Category implements Serializable { 

    @Transient 
    private static final long serialVersionUID = 1L; 

    @Id 
    @GeneratedValue 
    private Long id; 
    @Column(name = "category_name") 
    private String name; 

    @OneToMany(fetch = FetchType.EAGER, cascade = { CascadeType.ALL }, orphanRemoval = true) 
    @JoinTable(name = "policy_rule_mapping", 
    joinColumns = @JoinColumn(name = "category_id"), 
    inverseJoinColumns = @JoinColumn(name = "rule_id")) 
    private Set<AbstractPolicyRule> activePolicyRules; 

    ... 
} 

Esto tiene el mismo problema. La fila en la tabla de asignación se elimina pero AbstractPolicyRule aún contiene el elemento eliminado.

+0

El escenario que probé fue en realidad muy cercano a su edición. Cambié mi prueba para eliminar el elemento existente de la colección sin agregar otro y todavía se elimina. Sin embargo, tenga en cuenta que no estoy usando ninguna herencia (creo que podría ser). –

Respuesta

9

Estoy usando orphanRemoval=true con una asociación One-to-Many unidireccional sin ningún problema.

Y, de hecho, he probado su código y el siguiente escenario (AbstractPolicyRule implementar equals/hashCode correctamente):

Category category = new Category(); 
AbstractPolicyRule policyRule1 = new AbstractPolicyRule("foo"); 

category.addToActivePolicyRules(policyRule1); 
em.persist(category); 
em.flush(); 

assertNotNull(category.getId()); 
assertNotNull(category.getActivePolicyRules()); 
assertEquals(1, category.getActivePolicyRules().size()); 

category.removeFromActivePolicyRules(policyRule1); 
category.addToActivePolicyRules(new AbstractPolicyRule("bar")); 
// category = em.merge(category); // works with or without 
em.flush(); 
assertEquals(1, category.getActivePolicyRules().size()); 

simplemente funciona como se esperaba. Debajo de las trazas generadas:

 
22:54:30.817 [main] DEBUG org.hibernate.SQL - insert into Category (id, category_name) values (null, ?) 
Hibernate: insert into Category (id, category_name) values (null, ?) 
22:54:30.824 [main] TRACE org.hibernate.type.StringType - binding null to parameter: 1 
22:54:30.844 [main] DEBUG o.h.id.IdentifierGeneratorHelper - Natively generated identity: 1 
... 
22:54:30.872 [main] DEBUG org.hibernate.SQL - insert into AbstractPolicyRule (id, name) values (null, ?) 
Hibernate: insert into AbstractPolicyRule (id, name) values (null, ?) 
22:54:30.873 [main] TRACE org.hibernate.type.StringType - binding 'foo' to parameter: 1 
22:54:30.874 [main] DEBUG o.h.id.IdentifierGeneratorHelper - Natively generated identity: 1 
... 
22:54:30.924 [main] DEBUG org.hibernate.SQL - update AbstractPolicyRule set category_policy_id=? where id=? 
Hibernate: update AbstractPolicyRule set category_policy_id=? where id=? 
22:54:30.927 [main] TRACE org.hibernate.type.LongType - binding '1' to parameter: 1 
22:54:30.928 [main] TRACE org.hibernate.type.LongType - binding '1' to parameter: 2 
22:54:30.929 [main] DEBUG o.h.p.c.AbstractCollectionPersister - done inserting collection: 1 rows inserted 
22:54:30.929 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - Executing batch size: 1 
... 
22:54:30.945 [main] DEBUG org.hibernate.SQL - insert into AbstractPolicyRule (id, name) values (null, ?) 
Hibernate: insert into AbstractPolicyRule (id, name) values (null, ?) 
22:54:30.948 [main] TRACE org.hibernate.type.StringType - binding 'bar' to parameter: 1 
22:54:30.948 [main] DEBUG o.h.id.IdentifierGeneratorHelper - Natively generated identity: 2 
... 
22:54:30.990 [main] DEBUG org.hibernate.SQL - update AbstractPolicyRule set category_policy_id=null where category_policy_id=? and id=? 
Hibernate: update AbstractPolicyRule set category_policy_id=null where category_policy_id=? and id=? 
22:54:30.991 [main] TRACE org.hibernate.type.LongType - binding '1' to parameter: 1 
22:54:30.992 [main] TRACE org.hibernate.type.LongType - binding '1' to parameter: 2 
22:54:30.993 [main] DEBUG o.h.p.c.AbstractCollectionPersister - done deleting collection rows: 1 deleted 
22:54:30.993 [main] DEBUG o.h.p.c.AbstractCollectionPersister - Inserting rows of collection: [com.stackoverflow.q3304092.Category.activePolicyRules#1] 
22:54:30.994 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - Executing batch size: 1 
... 
22:54:30.996 [main] DEBUG org.hibernate.SQL - update AbstractPolicyRule set category_policy_id=? where id=? 
Hibernate: update AbstractPolicyRule set category_policy_id=? where id=? 
22:54:30.997 [main] TRACE org.hibernate.type.LongType - binding '1' to parameter: 1 
22:54:30.998 [main] TRACE org.hibernate.type.LongType - binding '2' to parameter: 2 
22:54:31.002 [main] DEBUG o.h.p.c.AbstractCollectionPersister - done inserting rows: 1 inserted 
... 
22:54:31.015 [main] DEBUG org.hibernate.SQL - delete from AbstractPolicyRule where id=? 
Hibernate: delete from AbstractPolicyRule where id=? 
22:54:31.017 [main] TRACE org.hibernate.type.LongType - binding '1' to parameter: 1 

Se elimina la primera regla de política.

Si esto no es representativo de lo que estás haciendo, deberías proporcionar más código.

Actualización: Responder a un comentario de la OP ...

¡me acaba de cambiar la llamada saveOrUpdate fusionar y ahora es la eliminación adecuada. ¿Tienes alguna idea de por qué es eso?

Sólo una conjetura: desde orphanRemoval es una cosa de la APP, me pregunto si se saveOrUpdate tratar apropiadamente con ella (en realidad, pensé que estaba utilizando la API EntityManager ya que ha mencionado APP).

+0

Gracias por la respuesta. Actualicé mi publicación con más información que, con suerte, tiene sentido. – Josh

+0

Quizás no entiendo lo que significa "establecer correctamente el código equies/hash". En este momento, el código equals/hash está usando los identificadores únicos para la tabla (pero no el id). – Josh

+0

@Josh Esa es una buena implementación (y utilicé tal implementación arriba cuando intento reproducir el problema). –

3

Primero asegúrese de que sus clases implementen los métodos hashCode() y equals(), de modo que hibernate sepa exactamente que estos elementos se eliminan del conjunto.

A continuación, intente definir la anotación de hibernación @Cascade, especificando el tipo de eliminación de huérfano de eliminación allí y observe si sucede lo mismo. Si funciona de la manera que lo desea, informe un error en hibernación y use temporalmente la anotación propietaria. De lo contrario, actualice la pregunta con los detalles

+0

Gracias por la respuesta. He actualizado mi publicación con más información. – Josh

Cuestiones relacionadas