简体   繁体   中英

Spring Data JPA : Repository DeleteById method not working

I have an issue which I do not understand with my Spring Data JPA Repository. I have the following entity:


@Entity
public class Ability {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;
    private String name;
    private String color;
    private String image;

    @ManyToOne(
            fetch = FetchType.EAGER
    )
    private Subject subject;

    @OneToMany(
            mappedBy = "ability",
            cascade = CascadeType.ALL,
            orphanRemoval = true,
            fetch = FetchType.EAGER
    )
    private Set<Technology> technologies;

And a JPA Repository for this entity. What I dot not understand, is that when I use the deleteById method of my Jpa Repository, the record is not deleted from the database. Strange thing is that it works fine in my integration test using an InMemory database. It works if I override the deleteById with the following:

    @Modifying
    @Query("DELETE FROM Ability a WHERE a.id = :id")
    void deleteById(@Param("id") Integer id);

But I suspect I shouldn't have to do that. Any clue with the method does not work as expected?

EDIT: Add endpoint source code

@RestController
@RequestMapping("/subjects/{subjectId}/abilities")
public class AbilityController {
    ...
    
    private final AbilityRepository abilityRepository;
    private final TechnologyRepository technologyRepository;
    private final SubjectRepository subjectRepository;

    public AbilityController(AbilityRepository abilityRepository, TechnologyRepository technologyRepository, SubjectRepository subjectRepository) {
        this.abilityRepository = abilityRepository;
        this.technologyRepository = technologyRepository;
        this.subjectRepository = subjectRepository;
    }

    @DeleteMapping("{abilityId}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void deleteAbility(@PathVariable("subjectId") Integer subjectId, @PathVariable("abilityId") Integer abilityId) {
        if (!abilityRepository.existsAbilityBySubjectId(subjectId, abilityId)) {
            throw new ResourceNotFoundException(String.format("No ability with Id : %s", abilityId));
        }

        abilityRepository.deleteById(abilityId);
    }
    ...
}

EDIT: Add Hibernate SQL

Hibernate: 
    select
        ability0_.id as id1_0_0_,
        ability0_.color as color2_0_0_,
        ability0_.image as image3_0_0_,
        ability0_.name as name4_0_0_,
        ability0_.subject_id as subject_5_0_0_,
        subject1_.id as id1_7_1_,
        subject1_.icon as icon2_7_1_,
        subject1_.image as image3_7_1_,
        subject1_.name as name4_7_1_,
        technologi2_.ability_id as ability_4_8_2_,
        technologi2_.id as id1_8_2_,
        technologi2_.id as id1_8_3_,
        technologi2_.ability_id as ability_4_8_3_,
        technologi2_.image as image2_8_3_,
        technologi2_.name as name3_8_3_ 
    from
        ability ability0_ 
    left outer join
        subject subject1_ 
            on ability0_.subject_id=subject1_.id 
    left outer join
        technology technologi2_ 
            on ability0_.id=technologi2_.ability_id 
    where
        ability0_.id=?
Hibernate: 
    select
        abilities0_.subject_id as subject_5_0_0_,
        abilities0_.id as id1_0_0_,
        abilities0_.id as id1_0_1_,
        abilities0_.color as color2_0_1_,
        abilities0_.image as image3_0_1_,
        abilities0_.name as name4_0_1_,
        abilities0_.subject_id as subject_5_0_1_ 
    from
        ability abilities0_ 
    where
        abilities0_.subject_id=?
Hibernate: 
    select
        technologi0_.ability_id as ability_4_8_0_,
        technologi0_.id as id1_8_0_,
        technologi0_.id as id1_8_1_,
        technologi0_.ability_id as ability_4_8_1_,
        technologi0_.image as image2_8_1_,
        technologi0_.name as name3_8_1_ 
    from
        technology technologi0_ 
    where
        technologi0_.ability_id=?

Thanks in advance

The "problem" is your mapping. Your collection is retrieved eagerly. Now why would that be an issue? The deleteById in Spring Data JPA first does a findById which in your case, loads the associated entities eagerly.

Now entity is attempting to be deleted but due to it being still attached and referenced by another entity it would be persisted again, hence the delete is canceled.

Possible solutions:

  • Delete using a query and write your own query method for this
  • Mark either side of the association lazy

Example:

@Entity
public class Ability {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;
    private String name;
    private String color;
    private String image;

    @ManyToOne(
            fetch = FetchType.LAZY
    )
    private Subject subject;

    @OneToMany(
            mappedBy = "ability",
            cascade = CascadeType.ALL,
            orphanRemoval = true,
            fetch = FetchType.LAZY
    )
    private Set<Technology> technologies;
}

@Repository
public interface AbilityRepository extends CrudRepository<Ability, Integer> {
}

Controller:

abilityRepository.deleteById(abilityId);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM