【问题标题】:Spring Pageable does not translate @Column nameSpring Pageable 不翻译 @Column 名称
【发布时间】:2018-12-29 18:39:56
【问题描述】:

我有实体对象:

@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&amp;page=0&amp;size=20

但是当我添加排序信息时它不起作用: http://localhost:8080/someEntity/search/findBySomeParameter?parameter=25&amp;page=0&amp;size=20&amp;sort=entityFieldName,asc 将抛出以下异常(我使用的是 Oracle 数据库):

Caused by: java.sql.SQLSyntaxErrorException: ORA-00904: "ENTITYFIELDNAME": invalid identifier

似乎排序字段没有用@Column(name) 翻译,而是内联到SQL 查询中。

有什么方法可以翻译可分页排序,使其不使用字段名而是使用列名?

【问题讨论】:

    标签: java spring-boot spring-data-jpa spring-rest


    【解决方案1】:

    article 阐明了这个问题。从第 3.1 节开始阅读。

    本机查询显然不支持动态排序。实际上,如果您将 findBySomeParameter 方法更改为采用 Sort 而不是 Pageable,您将获得 org.springframework.data.jpa.repository.query.InvalidJpaQueryMethodException: Cannot use native queries with dynamic sorting

    使用 pageable 不会出现异常,而且分页实际上似乎工作正常,但动态排序不会像您发现的那样替换列名。在我看来,唯一的解决方案是使用 JPQL 而不是本机查询,只要您需要进行的查询是您提供的查询,这不是问题。您需要将视图映射到 SomeEntityView 类才能使用 JPQL。

    编辑 我以为这个问题没有记录在案,但它实际上在official doc

    Spring Data JPA 目前不支持本地查询的动态排序,因为它必须操作声明的实际查询,而对于本地 SQL,它不能可靠地做到这一点。但是,您可以通过自己指定计数查询来使用本机查询进行分页,如下例所示:

    【讨论】:

    • 您的解决方案是我解决该问题的方法之一。我认为 spring 团队提供了一些 Claas/注释可以提供帮助。无论如何感谢您的回复! :)
    • 我刚刚添加了关于这个问题的官方文档警告,所以我猜他们没有解决方法
    【解决方案2】:

    此解决方法在 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));
        }
    
    

    【讨论】:

      猜你喜欢
      • 2017-03-22
      • 1970-01-01
      • 2016-07-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-05
      相关资源
      最近更新 更多