为什么手动定义的Spring Data JPA删除查询不会触发级联?

时间:2014-05-03 10:27:20

标签: jpa spring-data-jpa jpql cascade cascading-deletes

我遇到以下问题:当我尝试删除具有以下关系的实体时:

@OneToMany(mappedBy="pricingScheme", cascade=CascadeType.ALL, orphanRemoval=true)
private Collection<ChargeableElement> chargeableElements;

通过提供的删除方法CrudRepository,它删除了实体及其所有可收费元素,这很好。当我尝试使用自定义删除时出现问题:

@Modifying
@Query("DELETE FROM PricingScheme p WHERE p.listkeyId = :listkeyId")
void deleteByListkeyId(@Param("listkeyId") Integer listkeyId);

它说:

com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: 
  Cannot delete or update a parent row: a foreign key constraint fails
  (`listkey`.`chargeableelements`, CONSTRAINT `FK_pox231t1sfhadv3vy7ahsc1wt` 
  FOREIGN KEY (`pricingScheme_id`) REFERENCES `pricingschemes` (`id`))

为什么我不允许这样做? @Query方法不支持级联属性吗?我知道我可以先findByListkeyId(…)然后使用标准删除方法删除持久化实体,但它不够优雅。是否可以按照我尝试的方式使用自定义@Query方法?

2 个答案:

答案 0 :(得分:4)

这与Spring Data JPA无关,但是JPA指定它的工作方式(第4.10节 - &#34;批量更新和删除操作&#34;,JPA 2.0规范):

  

删除操作仅适用于指定类及其子类的实体。它不会级联到相关实体。

如果你考虑一下,JPA级联不是数据库级别的级联,而是由EntityManager维护的级联。因此,EntityManager需要知道要删除的实体实例及其相关实例。如果您触发查询,它实际上无法了解这些查询,因为持久性提供程序将其转换为SQL并执行它。因此,EntityManager无法分析对象图,因为执行完全发生在数据库中。

可以在over here找到与此主题相关的问答。

答案 1 :(得分:2)

我遇到了同样的问题,为了解决这个问题,我在@Modifying注释中添加了属性 clearAutomatically ,其值为true。

@Modifying(clearAutomatically = true)
@Query("delete User u where u.id = :userId")
void deleteUserById(@Param("userId") Long userId);

除此之外,删除实体的服务方法也使用 @Transaction 和插入用户的方法进行注释。