Home > front end >  Spring JPA - Removing all child entities instead of one
Spring JPA - Removing all child entities instead of one

Time:01-13

I have a Spring Boot app that uses Spring JPA which performs actions on a parent/child, OneToMany database relationship. I have been perfoming save and get requests without issue for a while however I now have a need to remove a child entity from the child database table, however when I test my code I find it removes all child entities from the DB AND the parent entity which is not the behaviour I am looking for.

Below are the entity classes, Zoo is the parent, and Animal is the child. They should have a oneToMany relation.

The parent entity.

import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;

import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;

import com.fasterxml.jackson.annotation.JsonManagedReference;

@Entity
@Table(name = "ZOOS")
public class Zoo {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", nullable = false, unique = true)
    private Integer id;
    
    @ManyToOne
    @JoinColumn(name="name")
    private String name;
    
    @OneToMany(mappedBy = "zoo", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @Fetch(value = FetchMode.SUBSELECT)
    @JsonManagedReference
    private List<Animal> animal;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public List<Animal> getAnimal() {
        return animal;
    }

    public void setAnimal(List<Animal> animal) {
        this.animal = animal;
    }
    
}

The child entity

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

import com.fasterxml.jackson.annotation.JsonBackReference;

@Entity
@Table(name = "ANIMALS")
public class Animal {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", nullable = false, unique = true)
    private Integer id;
    
    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "zooId")
    @JsonBackReference
    private Zoo zoo;
    
    @Column(name = "species", nullable = false)
    private String species;


    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Zoo getZoo() {
        return zoo;
    }

    public void setZoo(Zoo zoo) {
        this.zoo = zoo;
    }

    public String getSpecies() {
        return species;
    }

    public void setSpecies(String species) {
        this.species = species;
    }

}

The repo for the Animal (child) entity

import org.springframework.data.jpa.repository.JpaRepository;

import uk.co.example.api.entities.Animal;

public interface AnimalRepository extends JpaRepository<Animal, Integer> {

}

The java method being called to delete the animal entity

    @Autowired
    AnimalRepository animalRepo;
    
    public void deleteAnimal(Integer animalId) {
        animalRepo.deleteById(animalId);
    }
    

The method should remove one animal from the Animal db table, however in practice it is removing ALL animals with the same zooId and the zoo from the Zoo db table.

I have researched and tried changing the CascadeType.ALL on the ManyToOne annotation in the Animal entity class to PERSIST and I've tried removing the cascade parameter altogether, in both cases I found I would get no errors in my app but no animal records would be removed at all. The tables would be in the same state as before the method was run.

I have also tried using 'orphanRemoval = true' on the OneToMany annotation on the Zoo entity class however this doesn't seem to have any impact when testing.

@OneToMany(mappedBy = "zoo", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
    @Fetch(value = FetchMode.SUBSELECT)
    @JsonManagedReference
    private List<Animal> animal;

Any help will be appreciated.

CodePudding user response:

The relationship from Animal to Zoo is wrong

@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "zooId")
@JsonBackReference
private Zoo zoo;

With CascateType.ALL if you delete an Animal also, the Zoo will be deleted, and this will issue to delete all animals.

You should remove the cascading because it in most cases doesn't make sense

  • Related