【问题标题】:Why does a manually defined Spring Data JPA delete query not trigger cascades?为什么手动定义的 Spring Data JPA 删除查询不会触发级联?
【发布时间】:2014-06-20 00:37:47
【问题描述】:

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

@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 方法?

【问题讨论】:

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


    【解决方案1】:

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

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

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

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

    【讨论】:

      【解决方案2】:

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

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

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

      【讨论】:

      • clearAutomatically 与数据库级联无关。而是清除 entityManager 上下文。
      猜你喜欢
      • 2016-07-29
      • 2017-02-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-25
      • 2015-12-07
      • 2016-01-21
      相关资源
      最近更新 更多