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



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

我有一个场景,用户可以"批量更新"大量记录,并选择一些他们想要更新的值。按照旧的方式,代码手动构建了带有In语句的update语句,In语句用于PK的where(要更新哪些项),还手动构建了SET子句(其中SET子句中的选项可能因用户想要更新的内容而异)。

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

我试着用Spring Data JPA寻找一种方法来实现这一点,但没有任何运气。有没有我缺少的转发接口,或者需要另一个库。。。。还是我需要将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);
}

如果您希望您的模型类可以与自定义方法一起重用,那么还有@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);
}

有关更多信息,请查看spring数据参考文档中的repositories.custom-elementations、jpa.query-methods.at-query和jpa.query-methods.named-query。

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

其中SET子句中的选项可以根据用户的不同而变化想要更新

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

在我看到你的问题后,我试图为spring和QueryDSL集成寻找一些新的东西(你知道,也许在过去的几个月里发布了一些东西),但什么都没有发布。

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

  1. 获取要更新的实体的id
  2. 通过这些id检索所有实体(对数据库的第一个实际查询)
  3. 以任何方式修改它们
  4. 调用entityManager.flush,从而对数据库进行N次单独更新

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

我建议

自动将queryFactory连接到自定义存储库实现

此外,请查看spring数据和querydsl示例。但是,您只能找到查找示例。

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

最新更新