JPQL 查询删除不接受声明的 JOIN?

Posted

技术标签:

【中文标题】JPQL 查询删除不接受声明的 JOIN?【英文标题】:JPQL query delete not accept a declared JOIN? 【发布时间】:2018-08-21 18:01:56 【问题描述】:

我试图理解为什么 Hibernate 不接受这个遵循 JPQL:

@Modifying
@Query("delete from Order order JOIN order.credit credit WHERE credit.id IN ?1")
void deleteWithListaIds(List<Long> ids);

我收到的错误是:

Caused by: java.lang.IllegalArgumentException: node to traverse cannot be null!
    at org.hibernate.hql.internal.ast.util.NodeTraverser.traverseDepthFirst(NodeTraverser.java:46)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.parse(QueryTranslatorImpl.java:284)

但接受这个:

@Modifying
@Query("delete from Order order WHERE order.credit.id IN ?1")
void deleteWithListaIds(List<Long> ids);

实体Order(实体Credit不映射Orders):

@Entity
public class Order 

    @Id
    @Setter
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SEQUENCE)
    @SequenceGenerator(name = SEQUENCE, sequenceName = SEQUENCE, allocationSize = 1)
    @Column(name = "id", nullable = false)
    private Long id;

    @JoinColumn(name = "credit_id", foreignKey = @ForeignKey(name = "fk_order_credit"))
    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    private Credit credit;



select 语句中,这两种方法都被接受,但我不明白为什么 Hibernate 有这个限制,或者我在 DELETE Jpql 中做错了什么。我想在查询中声明 JOIN。

我知道在更复杂的查询中解决这个问题的唯一方法是创建一个子选择:

delete from Order order WHERE order.id IN (
    SELECT order.id FROM Order order
    JOIN order.credit credit
    WHERE credit.id in ?1)

这是更复杂的删除查询的正确方法吗?

我在上面的代码和 Spring Boot 1.5.10.RELEASE 中使用 Spring Jpa 存储库。

【问题讨论】:

您能否发布关系参数(即如何定义 Credit 和 Credit in Order) @osamayaccoub 谢谢,我用相关代码编辑了问题。 你也可以允许hibernate记录查询并检查生成的查询......我认为最终生成的查询不会相同......还有一些数据库对从多个表中删除有限制......你使用的是哪个数据库引擎***.com/questions/783726/… 【参考方案1】:

我不明白为什么 Hibernate 有这个限制。

在第 4.10 节的JPA Spec 中如此指定:

delete_statement ::= delete_clause [where_clause]
delete_clause ::= DELETE FROM entity_name [[AS] identification_variable]

所以删除语句中不允许连接。 为什么以这种方式决定这纯粹是我的猜测。 但是select_clausedelete_clause 指定查询操作的对象。虽然 select 语句对多个实体的组合进行操作是完全可以的,但用于删除的连接并没有多大意义。 它只是强制您指定要删除的实体。

我知道在更复杂的查询中解决这个问题的唯一方法是创建一个子选择:

这是更复杂的删除查询的正确方法吗?

如果你不能用更简单的方式表达它,那么是的,这就是要走的路。

【讨论】:

【参考方案2】:

您可以选择使用原生 SQL,而不是 JPQL, 但这可能会导致一些不便(例如无法进行排序)

所以要使用原生 SQL,只需添加 nativeQuery = true @Query(value = "...", nativeQuery = true)

欲了解更多信息,请转到here

【讨论】:

问题是关于使用 JPQL。不使用 JPQL 并不是一个好的答案(提问者可能知道他也可以使用原生 SQL)。另外,我不明白为什么您不能使用本机 SQL 进行排序。

以上是关于JPQL 查询删除不接受声明的 JOIN?的主要内容,如果未能解决你的问题,请参考以下文章

如何在一个 JPQL 查询中使用多个 JOIN FETCH

JPQL 动态查询接受多天

JPQL JOIN 查询对应值的行数(多列)

当我尝试进行 JPQL JOIN 查询时发生 ***Error

JPQL 外键查询

JPA JPQL - 如果不使用子对象(没有主键/外键关系)并且可以删除,则返回的查询