使用SpringData JPA,QueryDSL更新一堆记录

Use Spring Data JPA, QueryDSL to update a bunch of records

我正在重构代码库以摆脱 SQL 语句和原始访问并使用 Spring Data JPA(由休眠支持)进行现代化。我确实在项目中使用了QueryDSL用于其他用途。

我有一个场景,用户可以 "mass update" 大量记录,select 一些他们想要更新的值。在旧方法中,代码手动构建更新语句,其中包含用于 PK 位置(要更新哪些项目)的 IN 语句,并且还手动构建 SET 子句(其中 SET 子句中的选项可以根据用户的不同而有所不同)想更新)。

在看QueryDSL的文档,说明它支持我想做的事情。 http://www.querydsl.com/static/querydsl/4.1.2/reference/html_single/#d0e399

我尝试寻找一种方法来使用 Spring Data JPA 执行此操作,但没有成功。是否有我缺少的 repostitory 接口,或者另一个需要的库....或者我是否需要将 queryFactory 自动连接到自定义存储库实现中并真正实现 QueryDSL 示例中的代码?

您可以编写自定义方法或使用 @Query 注释。

对于自定义方法;

public interface RecordRepository extends RecordRepositoryCustom, 
                                          CrudRepository<Record, Long> 
{
}

public interface RecordRepositoryCustom {
      // Custom method
      void massUpdateRecords(long... ids);
}

public class RecordRepositoryImpl implements RecordRepositoryCustom {
      @Override
      public void massUpdateRecords(long... ids) {
           //implement using em or querydsl
      }
}

对于@Query注解;

public interface RecordRepository extends CrudRepository<Record, Long> 
{
      @Query("update records set someColumn=someValue where id in :ids")
      void massUpdateRecords(@Param("ids") long... ids);
}

如果您希望模型 class 可通过自定义方法重复使用,还有 @NamedQuery 选项;

@Entity
@NamedQuery(name = "Record.massUpdateRecords", query = "update records set someColumn=someValue where id in :ids")
@Table(name = "records")
public class Record {   
      @Id
      @GeneratedValue(strategy = GenerationType.AUTO)
      private Long id;
      //rest of the entity...
}

public interface RecordRepository extends CrudRepository<Record, Long> 
{
      //this will use the namedquery
      void massUpdateRecords(@Param("ids") long... ids);
}

查看 repositories.custom-implementations, jpa.query-methods.at-query and jpa.query-methods.named-queries spring 数据参考文档了解更多信息。

这个问题对我来说很有趣,因为我正在使用您问题中提到的相同技术栈解决我当前项目中的这个问题。我们特别对您问题的第二部分感兴趣:

where the options in SET clauses can vary depending on what the user wants to update

我知道这是您可能不想得到的答案,但我们没有找到任何答案:( Spring 数据对于更新操作来说非常麻烦,尤其是在灵活性方面。

看到您的问题后,我尝试查找有关 spring 和 QueryDSL 集成的新内容(您知道,也许过去几个月发布了一些内容)但没有发布任何内容。

唯一让我非常接近的是实体管理器中的 .flush,这意味着您可以遵循以下场景:

  1. 获取要更新的实体的 ID
  2. 通过这些 ID 检索所有实体(对数据库的第一个实际查询
  3. 随心所欲地修改它们
  4. 调用 entityManager.flush 导致 N 次单独更新数据库

这种方法导致 N+1 个对数据库的实际查询,其中 N = 需要更新的 ID 数 。而且你在来回移动数据,这实际上也不好。

我建议

autowire a queryFactory into a custom repository implementation

此外,请查看 spring data and querydsl example。但是,您只会找到查找示例。

希望我的悲观回答对您有所帮助:)