Spring Data JPA:存储库DeleteById方法不起作用

Omb*_*lin 7 java spring jpa spring-data-jpa spring-boot

我的 Spring Data JPA 存储库有一个我不明白的问题。我有以下实体:


@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;
Run Code Online (Sandbox Code Playgroud)

以及该实体的 JPA 存储库。我不明白的是,当我使用deleteByIdJpa 存储库的方法时,记录不会从数据库中删除。奇怪的是,它在我使用 InMemory 数据库的集成测试中运行良好。如果我deleteById用以下内容覆盖它,它就会起作用:

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

但我怀疑我不应该这样做。该方法有任何线索无法按预期工作吗?

编辑:添加端点源代码

@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);
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

编辑:添加 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=?
Run Code Online (Sandbox Code Playgroud)

提前致谢

Aki*_*dic 20

“问题”是你的映射。您的收藏已被热切检索。现在为什么这会成为一个问题呢?Spring deleteByIdData JPA 中首先执行 findById,在您的情况下,它会急切地加载关联的实体。

现在实体正在尝试删除,但由于它仍然被另一个实体附加和引用,它将再次被持久化,因此删除被取消。

可能的解决方案:

  • 使用查询删除并为此编写自己的查询方法
  • 将关联的任一侧标记为惰性

例子:

@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> {
}
Run Code Online (Sandbox Code Playgroud)

控制器:

abilityRepository.deleteById(abilityId);
Run Code Online (Sandbox Code Playgroud)