Spring Pageable无法转换@Column名称

3

我有一个实体对象:

@Entity(name = "table")
public class SomeEntity {

    @Id
    @Column(name = "id_column_name")
    public final BigDecimal entityId;

    @Column(name = "table_column_name")
    public final String entityFieldName;

}

我有一个数据库视图定义如下:

CREATE OR REPLACE FORCE EDITIONABLE VIEW "V_TABLE" ("ID_COLUMN_NAME", "TABLE_COLUMN_NAME", "SOME_OTHER_COLUMN") AS ... (some SQL magic) 

我有一个包含自定义查询的代码库:

@RepositoryRestResource
interface SomeEntityRepository extends PagingAndSortingRepository<SomeEntity, BigDecimal> {

    @Query(value = "select id_column_name, table_column_name FROM V_TABLE where some_other_column = ?#{#parameter} order by ?#{#pageable}",
        countQuery = "SELECT count(*) from V_TABLE v where  some_other_column = ?#{#parameter}",
        nativeQuery = true)
    Page<SomeEntity> findBySomeParameter(@Param("parameter") long parameter, Pageable pageable);
} 

当我使用以下url请求标准数据时,一切正常: http://localhost:8080/someEntity/search/findBySomeParameter?parameter=25&page=0&size=20 但是当我添加排序信息时,它就无法工作了: http://localhost:8080/someEntity/search/findBySomeParameter?parameter=25&page=0&size=20&sort=entityFieldName,asc 将抛出以下异常(我正在使用Oracle数据库):
Caused by: java.sql.SQLSyntaxErrorException: ORA-00904: "ENTITYFIELDNAME": invalid identifier

似乎使用@Column(name)时,排序字段并没有被翻译,而是直接嵌入到SQL查询中。
有没有办法使可分页的排序被翻译,这样它就会使用列名而不是字段名呢?
2个回答

4
这篇文章涉及到技术问题,具体可参考这个网站第3.1节开始。 很明显,原生查询不支持动态排序。实际上,如果将findBySomeParameter方法更改为接受Sort而不是Pageable,则会收到InvalidJpaQueryMethodException异常。使用Pageable时,您不会收到异常,并且分页实际上似乎工作正常,但是动态排序不会替换列名。在我看来,唯一的解决方案是使用JPQL代替本地查询,只要您提供的查询是所需的查询就没有问题。然而,您需要将视图映射到SomeEntityView类以便使用JPQL。编辑:我认为该问题未经记录,但实际上在官方文档中有说明。Spring Data JPA目前不支持本地查询的动态排序,因为它必须操作声明的实际查询,这对于本地SQL无法可靠地执行。但是,您可以通过自己指定计数查询来使用本机查询进行分页,如下面的示例所示:

你的解决方案是我为那个问题想出的其中一种变通方法。我觉得Spring团队提供了一些类/注释可以帮助解决,但无论如何感谢你的回复! :) - Maciek Murawski
1
我刚刚在这个问题上添加了官方文档的警告,所以我猜他们没有解决这个问题的方法。 - Pedro

0

这个解决方法在SpringBoot 2.4.3中对我有效:

    @PersistenceContext
    private EntityManager entityManager;

// an object ptoperty name to a column name adapter
    private Pageable adaptSortColumnNames(Pageable pageable) {
        if (pageable.getSort().isSorted()) {
            SessionFactory sessionFactory;
            if (entityManager == null || (sessionFactory = entityManager.getEntityManagerFactory().unwrap(SessionFactory.class)) == null)
                return pageable;
            AbstractEntityPersister persister = (AbstractEntityPersister) ((MetamodelImplementor) sessionFactory.getMetamodel()).entityPersister(CommentEntity.class);
            Sort adaptedSort = pageable.getSort().get().limit(1).map(order -> {
                String propertyName = order.getProperty();
                String columnName = persister.getPropertyColumnNames(propertyName)[0];
                return Sort.by(order.getDirection(), columnName);
            }).findFirst().get();
            return PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), adaptedSort);
        }
        return pageable;
    }

    @GetMapping()
    public ResponseEntity<PagedResponse<CommentResponse>> findByTextContainingFts(@RequestParam(value = "text", required = false) String text, Pageable pageable) {
// apply this adapter in controller
        pageable = adaptSortColumnNames(pageable);
        Page<CommentEntity> page = commentRepository.find(text, pageable);
        return ResponseEntity.ok().body(domainMapper.fromPageToPagedResponse(page));
    }


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接