简体   繁体   English

使用Spring Data JPA,QueryDSL更新一堆记录

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

I'm refactoring a code base to get rid of SQL statements and primitive access and modernize with Spring Data JPA (backed by hibernate). 我正在重构代码库,以摆脱SQL语句和原始访问,并使用Spring Data JPA(由hibernate支持)进行现代化。 I do use QueryDSL in the project for other uses. 我在项目中确实将QueryDSL用于其他用途。

I have a scenario where the user can "mass update" a ton of records, and select some values that they want to update. 我有一个场景,用户可以“大量更新”大量记录,并选择他们想要更新的一些值。 In the old way, the code manually built the update statement with an IN statement for the where for the PK (which items to update), and also manually built the SET clauses (where the options in SET clauses can vary depending on what the user wants to update). 以旧的方式,代码使用IN语句为PK的位置(要更新的项目)手动构建了更新语句,还手动构建了SET子句(其中SET子句中的选项会根据用户的不同而有所不同)。想要更新)。

In looking at QueryDSL documentation, it shows that it supports what I want to do. 在查看QueryDSL文档时,它表明它支持我想要做的事情。 http://www.querydsl.com/static/querydsl/4.1.2/reference/html_single/#d0e399 http://www.querydsl.com/static/querydsl/4.1.2/reference/html_single/#d0e399

I tried looking for a way to do this with Spring Data JPA, and haven't had any luck. 我试图寻找一种使用Spring Data JPA做到这一点的方法,但是没有任何运气。 Is there a repostitory interface I'm missing, or another library that is required....or would I need to autowire a queryFactory into a custom repository implementation and very literally implement the code in the QueryDSL example? 是否有我缺少的重新发布接口,或是否需要另一个库...。或者我需要将queryFactory自动连接到自定义存储库实现中,并从字面上实现QueryDSL示例中的代码?

You can either write a custom method or use @Query annotation. 您可以编写自定义方法,也可以使用@Query注释。

For custom method; 对于自定义方法;

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
      }
}

For @Query annotation; 对于@Query注释;

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

There is also @NamedQuery option if you want your model class to be reusable with custom methods; 如果您希望模型类可通过自定义方法重用,则还有@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);
}

Check repositories.custom-implementations , jpa.query-methods.at-query and jpa.query-methods.named-queries at spring data reference document for more info. 请在spring数据参考文档中检查repositories.custom-implementationsjpa.query-methods.at-queryjpa.query-methods.named-query以获得更多信息。

This question is quite interesting for me because I was solving this very problem in my current project with the same technology stack mentioned in your question. 这个问题对我来说很有趣,因为我正在使用您的问题中提到的相同技术堆栈在当前项目中解决这个问题。 Particularly we were interested in the second part of your question: 我们特别对您问题的第二部分感兴趣:

where the options in SET clauses can vary depending on what the user wants to update SET子句中的选项可能会有所不同,具体取决于用户要更新的内容

I do understand this is the answer you probably do not want to get but we did not find anything out there :( Spring data is quite cumbersome for update operations especially when it comes to their flexibility. 我确实理解这是您可能不想得到的答案,但是我们没有找到任何答案:( Spring数据对于更新操作非常麻烦,尤其是在灵活性方面。

After I saw your question I tried to look up something new for spring and QueryDSL integration (you know, maybe something was released during past months) but nothing was released. 看到您的问题后,我尝试查找有关Spring和QueryDSL集成的新内容(您可能知道过去几个月中发布了一些内容),但未发布任何内容。

The only thing that brought me quite close is .flush in entity manager meaning you could follow the following scenario: 使我非常接近的唯一一件事是实体管理器中的.flush ,这意味着您可以遵循以下情形:

  1. Get ids of entities you want to update 获取您要更新的实体的ID
  2. Retrieve all entities by these ids ( first actual query to db ) 通过这些ID检索所有实体( 对db的第一个实际查询
  3. Modify them in any way you want 以您想要的任何方式修改它们
  4. Call entityManager.flush resulting N separate updates to database . 调用entityManager.flush 对数据库进行N次单独更新

This approach results N+1 actual queries to database where N = number of ids needed to be updated. 这种方法导致对数据库进行N + 1次实际查询 ,其中N =需要更新的ID数 Moreover you are moving the data back and forth which is actually not good too. 此外,您正在来回移动数据,这实际上也不是一件好事。

I would advise to 我建议

autowire a queryFactory into a custom repository implementation 自动将queryFactory连接到自定义存储库实现中

Also, have a look into spring data and querydsl example . 另外,请查看spring数据和querydsl示例 However you will find only lookup examples. 但是,您只会找到查找示例。

Hope my pessimistic answer helps :) 希望我的悲观答案有帮助:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM