6

I have 2 entities: Group and Grouped, with 1 ManyToMany association.

In database, the Association table has a NOT NULL FK on both Group and Grouped.

I want Hibernate to delete the association but not the group when all grouped are deleted.

Code to delete a Grouped entity:

@Autowired
private final GroupedRepository groupedRepository;

public void delete(Grouped groupedToRemove) {
    groupedRepository.delete(groupedToRemove);
}

If I set cascade = CascadeType.ALL or cascade = CascadeType.REMOVE, my Group entities are deleted when I delete a Grouped entity, not only the associations:

@ManyToMany(cascade = CascadeType.ALL, // same behavior with CascadeType.REMOVE
        mappedBy = "grouped", 
        targetEntity = Group.class)
private Set<Group> groups = new HashSet<>();

If I remove the cascade, hibernate tries to set group_id=null and it throws a ModelConstraintException. I don't want to set the FK as nullable.

Group entity:

@Entity
@Table(name = "groups")
@Getter
@Setter
public class Group {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    @ManyToMany(targetEntity = Grouped.class)
    @JoinTable(
            name = "association",
            joinColumns = @JoinColumn(name = "group_id", nullable = false, updatable = false),
            inverseJoinColumns = @JoinColumn(name = "grouped_id", nullable = false, updatable = false)
    )
    private Set<Grouped> grouped= new HashSet<>();
}

Grouped entity:

@Entity
@Table(name = "grouped")
@Getter
@Setter
public class Grouped {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    @ManyToMany(mappedBy = "grouped", targetEntity = Group.class)
    private Set<Group> groups= new HashSet<>();
}
Pleymor
  • 2,611
  • 1
  • 32
  • 44

1 Answers1

6

That's the expected behavior. REMOVE cascading means: when removing this entity, also remove the associated entities. It makes no sense on a ManyToXxx, since obviously, other entities are still referencing the associated entity.

If you want to delete a Grouped, but leave the associated Groups there, you need to remove the association between the two entities first:

for (Group group : grouped.getGroups()) {
    group.getGrouped().remove(grouped);
}
grouped.getGroups().clear();

and then remove the Grouped entity, which is not associated to any Group anymore.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • Post the code of both entities, the code you're using to delete the grouped, and the complete stack trace of the exception. – JB Nizet Sep 02 '15 at 13:53
  • Yes, it works, thank you ! So the important here is :to delete all references of Group entities on the Grouped entity to delete, but also to delete all references of the Grouped to delete on all linked Group entities. – Pleymor Sep 02 '15 at 13:58
  • 1
    Which is what my code example does. Actually, the only side that really matters is the owner side, which is the side which does NOT have the `mappedBy` attribute. – JB Nizet Sep 02 '15 at 14:00
  • you mean we can remove grouped.getGroups().clear(); ? – Pleymor Sep 03 '15 at 13:48
  • 1
    Yes. I left it there because it's a good practice to modify both sides of an association in a coherent way. – JB Nizet Sep 03 '15 at 13:51