带 Join 的 JPQL 更新语句

JoJ*_*oJo 3 java hibernate jpa jpql

我以前从未使用过JPQL,我需要使用它来批量更新特定列中的值。该列存在于表中,但设置实体类时没有为其设置变量。我无法使用确切的数据,但设置如下所示,可以给您一个想法:

数据库列

Books:
book_id book_title author_id

Authors:
author_id first_name last_name
Run Code Online (Sandbox Code Playgroud)

JPA 实体类

Books:
private Integer bookId;
private String bookTitle;
private EAuthor author;

Authors:
private Integer authorId;
private String firstName;
private String lastName;
Run Code Online (Sandbox Code Playgroud)

在 Books 实体类中,author_id 有一个 getter 和 setter,但它是从作者实体调用的。我现在的困境是我需要批量更新具有相同author_id 的所有book_titles,并且我不确定如何编写JPQL 查询语句来执行此操作。我试过:

String queryUpdate = "UPDATE books b SET b.book_title = :bookTitle"
                            + " WHERE b.author = :authorId";
Run Code Online (Sandbox Code Playgroud)

String queryUpdate = "UPDATE books b SET b.book_title = :bookTitle"
                            + " WHERE b.author.authorId = :authorId";
Run Code Online (Sandbox Code Playgroud)

两个查询均表示 b.author.authorId 和 b.author 都是无效标识符。是否可以编写两个单独的查询?1 个查询作为选择语句,我可以在其中使用联接,然后使用第二个查询来更新第一个查询的结果集?

cri*_*zis 5

对于这项工作来说,JPQL 是一个糟糕的选择。b.author.authorId是不允许的,因为它会转换为 SQL JOIN。JPQL 也不支持UPDATE语句中的子查询。您可以将 映射author_id到以下位置的属性Books

@Column(name = "author_id", insertable=false, updatable=false)
private Long authorId;
Run Code Online (Sandbox Code Playgroud)

完成上述操作后,您可以执行以下操作:

UPDATE Books b SET b.book_title = :bookTitle WHERE b.authorId = :authorId
Run Code Online (Sandbox Code Playgroud)

但是您必须忍受更改域模型只是为了适应查询的单个案例UPDATE

您应该能够将任务分成两个查询,如下所示:

List<Long> ids = em.createQuery("SELECT b.id FROM Books b WHERE b.author.id = :authorId", Long.class)
    .setParameter("authorId", authorId)
    .getResultList();
em.createQuery("UPDATE Books b SET b.bookTitle = :bookTitle WHERE b.id IN :ids")
    .setParameter("ids", ids)
    .setParameter("bookTitle", bookTitle)
    .executeUpdate();
Run Code Online (Sandbox Code Playgroud)

或者,您可以简单地从代码更新实体:

em.createQuery("SELECT b.id FROM Books b WHERE b.author.id = :authorId", Book.class)
    .setParameter("authorId", authorId)
    .getResultList()
    .forEach(book -> book.setBookTitle(bookTitle));
Run Code Online (Sandbox Code Playgroud)