2011-04-12 17 views
6

Cómo elimino una entidad en una relación OneToMany.JPA2.0: Eliminar entidad en OneToMany RelationShip

@Entity 
@NamedQueries({ 
    @NamedQuery(name="User.findByUserNamePassword", 
    query="select c from User c where c.userName = :userName AND c.password = :password") 
}) 
@Table(name="\"USER\"") 
public class User implements Serializable { 
    @OneToMany(mappedBy="user", cascade=CascadeType.ALL, orphanRemove=true) 
    private List<Profession> professions; 

    public List<Profession> getProfessions() { 
     return professions; 
    } 

    public void setProfessions(List<Profession> professions) { 
     this.professions = professions; 
    } 

    public void addProfession(Profession profession){ 
     if(this.professions == null){ 
      this.professions = new ArrayList<Profession>(); 
     } 
     this.professions.add(profession); 
     profession.setUser(this); 
    } 

    public void removeProfession(Profession profession){ 
     if(this.professions != null){ 
      professions.remove(profession); 
      profession.setUser(null); 
     } 
    } 
} 

Dentro Profesión Entidad

@Entity 
public class Profession implements Serializable { 
    @ManyToOne 
    @JoinColumn(name="UserId", nullable=false) 
    private User user; 

    public User getUser() { 
     return user; 
    } 

    public void setUser(User user) { 
     this.user = user; 
    } 

A continuación, dentro de mi EJB tengo unas pocas cosas

@Stateless 
@LocalBean 
@TransactionAttribute(TransactionAttributeType.REQUIRED) 
public class ScholarEJB{ 

    /** 
    * Add a profession to a target user 
    * @param user 
    * @param profession 
    */ 
    public void addProfession(User user, Profession profession){ 
     //Put the user in a managed state. It is important to do this before 
     //adding a new profession onto user 
     user = find(User.class, user.getId()); 
     user.addProfession(profession); 
     this.create(user); //This is persist action 
    } 

    public void removeProfession(User user, Profession profession){ 
     //Put the user in a managed state. It is important to do this before 
     //adding a new profession onto user 
     user = find(User.class, user.getId()); 
     user.remove(user); 
     this.update(user); //merge action 
     //this.create(user) //also try this as well, but it does not work 
    } 
} 

Ahora addProfession trabajo muy bien, pero removeProfession no funciona. No estoy seguro por qué? Ayuda por favor. ¿Necesito expulsar cachés?

+0

En su relación de uno a muchos, la anotación correcta es orphanRemoval = true, no orphanRemove = true – greuze

Respuesta

1

Usted puede tratar de despejar el campo de usuario en la profesión:

public void removeProfession(Profession profession){ 
     if(this.professions != null){ 
      professions.remove(profession); 
      profession.setUser(null); // disassociate profession from user 
     } 
    } 

Para estar en el lado seguro, también me gustaría comprobar que la aprobada en el usuario actual de la profesión es igual this, por si acaso alguien pasa en una profesión perteneciente a otro usuario.

+0

tratan tan bien, que no funciona. Imprimo la lista de la profesión después de eliminar y antes de persistir/fusionar, la lista vuelve correcta. Pero cuando persisto/fusiono, esto no se refleja dentro de mi base de datos –

9

Si las profesiones son solo una parte de esta relación, puede garantizar que cuando una profesión se elimine del conjunto del usuario también se elimine de la base de datos activando orphanRemoval en el lado OneToMany de la relación.

@OneToMany(mappedBy="user", cascade=CascadeType.ALL, orphanRemoval=true) 
private List<Profession> professions; 

Esto es lo que los JPA 2.0 estados de especificación

La especificación JPA 2.0 establece que

asociaciones que se especifican como OneToOne o uso apoyo OneToMany de la opción orphanRemoval. Los comportamientos siguientes se aplican cuando orphanRemoval es en efecto:

Si una entidad que es el objetivo de la relación se elimina de la relación (mediante el establecimiento de la relación a null o extracción de la entidad de la relación colección), se aplicará la operación de eliminación a la entidad que es huérfana. La operación de eliminación es aplicada en el momento de la operación de descarga . La funcionalidad orphanRemoval está destinada a las entidades que son "propiedad privada" de su entidad matriz . Las aplicaciones portátiles no deben depender de un orden de eliminación específico , y deben no reasignar una entidad que ha sido huérfano a otra relación o de lo contrario intentarán persistir. Si la entidad que se deja huérfana es una entidad separada, nueva o eliminada de , la semántica de orphanRemoval no se aplica a .

Si la operación de eliminación se aplica a una entidad de origen administrado, la operación de eliminación será en cascada a la diana relación de acuerdo con las reglas de la sección 3.2.3, (y por lo tanto no es necesario especificar cascada = ELIMINAR para la relación ) [20].

+1

, por desgracia, lo intento, pero todavía no funciona. Pero me di cuenta de qué trabajo. Tengo que borrar el caché de segundo nivel para que esto funcione. 'profession = em.merge (profesión); em.remove (profesión); em.getEntityManagerFactory(). getCache(). evictAll(); ', este trabajo, pero no estoy seguro de si este es el mejor enfoque –

+0

¿Puede publicar lo que hace su método de actualización? Dice que realiza una combinación, que no es clara ni evidente en tu código actual. –

+0

Replico mi código. Por favor compruébelo –

1

Esta es la solución a mi pregunta original, sin embargo, no sé si este es el mejor

Mi EJB frijol

@PersistenceContext(unitName="Bridgeye2-ejbPU") 
private EntityManager em; 

public <T> T create(T t) { 
    em.persist(t); 
    return t; 
} 

public <T> T find(Class<T> type, Object id) { 
    return em.find(type, id); 
} 

public <T> void delete(T t) { 
    t = em.merge(t); 
    em.remove(t); 
} 

public <T> void removeAndClearCaches(T t){ 
    this.delete(t); 
    clearCaches(); 
} 

public <T> T update(T t) { 
    return em.merge(t);  

Ahora en mi bean gestionado, hago esto

/** 
* Add a new profession 
*/ 
public void addNewProfession(){ 
    Profession profession = new Profession();   
    newProfessions.add(profession);   
} 

/** 
* Remove the profession 
* @param profession 
*/ 
public void removeProfession(Profession profession){ 
    //This will remove the `profession` of the list 
    //at the presentation layer 
    this.myProfessions.remove(profession); 
    //This will remove the `profession` of the list 
    //at the persistence layer 
    scholarEJB.removeAndClearCaches(profession); 
} 
4

Supongo que lo que ocurre es que su usuario tiene una relación de OneToMany con la profesión y su objeto de usuario tiene la profesión. Cuando elimina la Profesión, el usuario todavía tiene la referencia. Debido a que el mapeo es en cascada, persiste la Profesión.

Debe asegurarse de eliminar la profesión de las profesiones del usuario antes de eliminarla.

Si está utilizando EclipseLink hay una propiedad que también puede ayudar, pero la mejor solución es corregir el código para mantener su modelo correctamente. También podría eliminar la cascada persistir.

"eclipselink.persistence-context.persist-on-commit" = "true"

o, "eclipselink.persistence-context.commit-sin-persistir-reglas" = "true"

0

Acabo de agregar orphanRemoval = true en la relación OneToMany y lo resolví.

Clase SolicitudRetorno:

@OneToMany(mappedBy = "solicitud", cascade = CascadeType.ALL, orphanRemoval = true) 
@LazyCollection(LazyCollectionOption.FALSE) 
@NotAudited 
private List<RetornoMenor> hijosRetorno; 

Clase RetornoMenor:

@OneToMany(mappedBy = "solicitud", cascade = CascadeType.ALL, orphanRemoval = true) 
@LazyCollection(LazyCollectionOption.FALSE) 
@NotAudited 
private List<RetornoMenor> hijosRetorno; 
Cuestiones relacionadas