CrudRepository多对一关联场景下按taskId和projectId删除TimeCard的正确查询方法咨询
解决Spring Data JPA删除TimeCard数据的命名错误问题
你的问题主要出在两个地方:Repository泛型类型错误和查询方法的命名不符合Spring Data JPA的属性表达式规则,下面一步步帮你解决:
1. 修正Repository泛型类型
首先看你的TimeCardRepository定义:
public interface TimeCardRepository extends CrudRepository<TimeCard, String>
TimeCard的主键timeCardId是Long类型,但你给CrudRepository的第二个泛型参数传了String,这会导致后续操作出现类型不匹配的问题,必须改成Long:
public interface TimeCardRepository extends CrudRepository<TimeCard, Long>
2. 修正删除方法的命名规则
Spring Data JPA的查询方法命名对大小写非常敏感,必须严格对应实体类中的属性名:
TimeCard类中的关联属性是小写的task,不是大写开头的TaskTask类中的关联属性是小写的project,不是大写开头的Project
你原来的方法名deleteTimeCardByTaskTaskIdAndTaskProjectProjectId里,把属性名的首字母大写了,导致JPA错误地将TaskProject识别成TimeCard的一个字段,从而抛出找不到字段的异常。
正确的方法名应该是:
void deleteByTaskTaskIdAndTaskProjectProjectId(int taskId, Long projectId);
解释一下命名逻辑:
deleteBy:表示这是一个删除操作,后面跟过滤条件TaskTaskId:对应TimeCard.task.taskId(task是TimeCard的属性,taskId是Task的属性)AndTaskProjectProjectId:对应TimeCard.task.project.projectId(project是Task的属性,projectId是Project的属性)- 不需要在
delete后面加TimeCard,因为Repository已经绑定了TimeCard实体,JPA会自动识别要操作的表
备选方案:使用@Query注解(更直观)
如果你觉得命名规则容易搞混,也可以用@Query注解直接写JPQL语句,这种方式更灵活,也不容易出错:
@Modifying @Query("DELETE FROM TimeCard tc WHERE tc.task.taskId = :taskId AND tc.task.project.projectId = :projectId") void deleteByTaskIdAndProjectId(@Param("taskId") int taskId, @Param("projectId") Long projectId);
注意要加上@Modifying注解,告诉Spring Data JPA这是一个写操作(删除属于修改操作)。
最终的Repository代码
把上面的修正整合起来,最终的TimeCardRepository应该是这样的:
@Repository public interface TimeCardRepository extends CrudRepository<TimeCard, Long>{ // 方法命名方式 void deleteByTaskTaskIdAndTaskProjectProjectId(int taskId, Long projectId); // 或者@Query方式(二选一即可) @Modifying @Query("DELETE FROM TimeCard tc WHERE tc.task.taskId = :taskId AND tc.task.project.projectId = :projectId") void deleteByTaskIdAndProjectId(@Param("taskId") int taskId, @Param("projectId") Long projectId); }
内容的提问来源于stack exchange,提问作者Babas
相关产品推荐
相关产品推荐

