Removing items from a OneToMany interface by default

1

I have an entity that has a list attribute of type OneToMany:

@Entity 
public class Pai {

    private List<Filho> filhos;
    //demais atributos...

    @OneToMany(mappedBy = "pai", cascade = CascadeType.ALL)
    public List<Staff> getFilhos() {
        return staffs;
    }

    public void setFilhos(List<Filho> filhos) {
        this.filhos = filhos;
    }
}

@Entity 
public class Filho {

    private Pai pai;
    //demais atributos...

    @ManyToOne
    @JoinColumn(name = "id_pai")
    public Pai getPai() {
        return pai;
    }

    public void setPai(Pai pai) {
        this.pai = pai;
    }

}

When I update, I get the whole structure, that is, the parent, along with the children and give the persist in the Father. Children with ID are updated and those without ID are included.

The question is, how to proceed when a child is removed? I just tried not to send it, ie omit it from the list and save the Father. It does not work, the son is still there.

What is the best approach to remove a child in such a relationship?

    
asked by anonymous 20.07.2016 / 17:42

1 answer

1

The child is an entity of its own and can exist even without a parent. Soon removing the relationship does not mean removing the child. To no longer appear in the database the child must be removed from the parent list and also must be removed from the persistence context directly by the entityManager.

For example, to remove child 0 from parent and database:

Pai pai = entityManager.find(Pai.class, 19L);
Filho filho = pai.getFilhos().remove(0);  // remove e retorna o elemento removido
entityManager.remove(filho);

But why in your example the child is not removed at least from the parent list?

Well, in the JPA specification:

  

The many side of one-to-many / many-to-one bidirectional relationships   hence the mappedBy element can not be   specified on the ManyToOne annotation.

     

(JSR 338 - Section 2.9 Entity Relantionships)

In your case, who is on the "many" side of the relationship is the Son. So he is the owner of the relationship! Removing a child from the parent class will not make a difference in the database because the parent is not the owner of the relationship.

To undo the relationship the parent must be removed from the child. The interesting thing would always be to do both, remove the father of the son and the son of the father, so the graph of entities is always consistent.

To remove by default the way you want, hibernate has the orphanRemoval option, where any child without a parent is automatically deleted, so simply remove the child from the parent list. To do this just change the @OneToMany in the parent class as follows:

@OneToMany(mappedBy = "pai", cascade = CascadeType.ALL, orphanRemoval = true)
public List<Staff> getFilhos() {
    return staffs;
}

This solution is hibernate specific and does not exist in JPA, but would be the most appropriate solution for your question.

Another option is to declare the relationship only on the parent side, by erasing the manyToOne in the child. In this case, hibernate will create a parent-child table which may be undesirable, by deleting the child from the parent list it will be removed from the relationship, but the child will continue to exist in the child table, but without a parent.

    
21.07.2016 / 13:57