davidszkl
davidszkl

Reputation: 1

Java SpringBoot JPA calling deleteById() on an entity with oneToMany() childs and oneToone() parent does not delete the child

I setup a simple hierarchy: Parent, Child, Subchild. a parent has one child, a child has oneToMany subchildren. I call childRepository.deleteById(), it does not delete neither the child nor the subchildren and it does not throw an error. Minimal setup to reproduce the issue:

Parent.Java:

@Entity
@Table(name = "PARENT")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Parent {
    @Id
    @Column(name = "ID")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @OneToOne(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
    private Child oneChild;
}

Child.Java:

@Entity
@Table(name = "CHILD")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Child {
    @Id
    @Column(name = "ID")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @OneToMany(mappedBy = "child", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<SubChild> subChilds = new HashSet<>();

    @OneToOne
    @JoinColumn(name = "PARENT_ID")
    private Parent parent;
}

SubChild.Java:

@Entity
@Table(name = "SUBCHILD")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SubChild {
    @Id
    @Column(name = "ID")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne
    @JoinColumn(name = "CHILD_ID")
    @EqualsAndHashCode.Exclude
    private Child child;
}

controller.Java:

private final ChildRepository childRepository;

public void deleteChild(Long id) {
        childRepository.deleteById(id);
    }

Upvotes: 0

Views: 54

Answers (1)

Reuven Eliezer
Reuven Eliezer

Reputation: 96

Cascading and orphan removal work when the entities are managed (e.g., loaded into the persistence context). If the entity isn't loaded, these settings have no effect.

You have 3 ways to handle it:

  1. Add "ON DELETE CASCADE" to your Sql statement:
 ALTER TABLE SUBCHILD ADD CONSTRAINT FK_CHILD
        FOREIGN KEY (CHILD_ID) REFERENCES CHILD(ID) ON DELETE CASCADE;
  1. Load the Child Entity before you remove it:
public void deleteChild(Long id) {
    Child child = childRepository.findById(id);
    childRepository.delete(child);
}
  1. Before you trying to delete the Child, you must to delete all entities related to him (SubChild), because of the SubChild holds the Child by REFERENCES (SQL) in Your SubChild class So, when you going to remove the Child, remove firstly the all SubChild related to him and after it, remove the Child entity better to do this under @Transactional like :
@Transactional
public void deleteChildAndSubChildren(Long id) {
      subChildRepository.deleteSubChildrenByChildId(id);
      childRepository.deleteById(id);
}

Upvotes: 0

Related Questions