Olá!
Estou tentando excluir uma entidade que possui uma coleção de entidades da mesma classe que ela mesma. Estou lidando com a montagem de um menu, aonde um item do menu pode ser uma ação ou então um submenu, composto de uma lista de ações ou de outros submenus (que por sua vez podem ter uma lista de ações ou submenus como filhos, e por aí vai).
O que gostaria de fazer é, quando eu excluir um item do menu, todos os subitems fossem excluídos também.
Abaixo estão minhas entidades.
A WebMenuItem é uma classe abstrata.
@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="tipoItem", discriminatorType=DiscriminatorType.STRING)
public abstract class WebMenuItem implements Comparable<WebMenuItem> {
@Id
@GeneratedValue
private Integer id;
@Column(nullable=false)
private Integer sequencia;
@ManyToOne
@JoinColumn(name="idMenu", nullable=false)
private WebMenu webMenu;
@ManyToOne
@JoinColumn(name="idSubmenuPai", referencedColumnName="id", nullable=true)
private WebSubmenu subMenuPai;
// Getters e Setters
// compareTo, equals, hashcode
}
A WebMenuPagina representa um item do menu que é uma ação (ou página), e extende a classe acima.
@Entity
public class WebMenuPagina extends WebMenuItem implements Serializable {
private static final long serialVersionUID = 1L;
@ManyToOne
@JoinColumn(name="url", referencedColumnName="url", nullable=true)
private WebPagina webPagina;
// Getter e Setter
}
A WebSubmenu representa um item do menu que por sua vez tem uma coleção de outros items do menu. Anotei a relação com CascadeType.ALL e orphanRemoval=true
@Entity
public class WebSubmenu extends WebMenuItem implements Serializable, WebMenuComFilhos {
private static final long serialVersionUID = 1L;
@OneToMany(mappedBy="subMenuPai", fetch=FetchType.EAGER, cascade=CascadeType.ALL, orphanRemoval=true)
@OrderBy("sequencia ASC")
private Set<WebMenuItem> itensFilhos;
@Column(nullable=true)
private String nome;
// Getters e Setters
@Transient
public void adicionaItemFilho(WebMenuItem item) {
itensFilhos.add(item);
}
@PreRemove
public void preRemove(){
this.itensFilhos.clear();
System.out.println("***** pre remove + " + this.getId() + " " + this.getNome() + " - " + this + ":: " + this.getSubMenuPai());
}
}
Quando executo um EntityManager.remove passando um submenu que possui “filhos” tenho o seguinte comportamento:
- o método anotado com @PreRemove da classe WebSubmenu é chamado para o submenu excluído, e todos os seus filhos (e filhos dos filhos, etc.)
- é executado um único comando SQL DELETE, para o último filho da árvore. Isto é, se um Submenu1 tem o filho Submenu2, que por sua vez tem um filho Submenu3, apenas o Submenu 3 é deletado.
Já havia feito um post sobre esse mesmo assunto (http://www.guj.com.br/java/292902-jpa---comportamento-cascadeall-onetomany) porém não consegui obter informações suficientes, e as classes foram alteradas um pouco, por isso fiz outro post.
Valeu!!!