为什么手动定义的Spring Data JPA删除查询不会触发级联? [英] Why does a manually defined Spring Data JPA delete query not trigger cascades?

查看:536
本文介绍了为什么手动定义的Spring Data JPA删除查询不会触发级联?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

通过提供的delete方法,使用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(…)然后使用标准的delete方法删除持久性实体,但这是不雅的.可以按照我尝试的方式使用自定义@Query方法吗?

解决方案

这与Spring Data JPA没有任何关系,但是JPA指定了它的工作方式(第4.10节-批量更新和删除操作",JPA 2.0规格):

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

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

可以在

with a CrudRepository through a provided delete method it removes the entity along with its all chargeable elements which is fine. The problem appears when I try to use my custom delete:

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

it says:

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`))

Why I am not allowed to do this? Does @Query methods do not support cascade property? I know I can findByListkeyId(…) first and then remove persistent entity with standard delete method, but it is inelegant. Is it possible to use a custom @Query method the way I tried to?

This has got nothing to do with Spring Data JPA but is the way JPA specifies this to work (section 4.10 - "Bulk Update and Delete Operations", JPA 2.0 specification):

A delete operation only applies to entities of the specified class and its subclasses. It does not cascade to related entities.

If you think about it, JPA cascades are not database-level cascades but ones maintained by the EntityManager. Hence, the EntityManager needs to know about the entity instance to be deleted and its related instances. If you trigger a query, it effectively can't know about those as the persistence provider translates it into SQL and executes it. So there's no way the EntityManager can analyze the object graph as the execution is completely happening in the database.

A question and answer related to this topic here can be found over here.

这篇关于为什么手动定义的Spring Data JPA删除查询不会触发级联?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆