Removing items from a Onetomany relation by default

Asked

Viewed 1,605 times

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 make an update, I receive the whole structure, that is, the father, together with the children and I 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 tried simply not to send it, i.e., omit it from the list and save the Father. It doesn’t work, the son is still there.

What’s the best approach to removing a child in a relationship like this?

1 answer

1


The child is an entity of its own and can exist even without a parent. So removing the relationship does not mean removing the child. To no longer appear in the database the child must be removed from the parent’s list and must also be removed from the persistence context directly by 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 his example the son is not removed at least from the father’s list?

Well, in the JPA specification:

The Many side of one-to-Many / Many-to-one bidirectional relationships must be the Owning side, Hence the mappedBy element cannot 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. Therefore he is the owner of the relationship! Removing a child from the Parent class will make no difference in the database because the parent is not the owner of the relationship.

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

To remove by default the way you want, Hibernate has the orphanRemoval option, where any fatherless child is automatically deleted, so simply remove the child from the parent list. For that just change @Onetomany in the parent class as follows:

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

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

Another option is to declare the relationship only on the father’s side, erasing the manyToOne on the son. In this case Hibernate will create an extra pai_filho table which can be unwanted, when deleting the child from the father’s list he will be removed from the relationship, but the child will continue to exist in his table, but without father.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.