Spring JPA Repository原生查询中的子查询

5

我试图在存储库方法上运行一个本地查询,以便返回一些计数的结果。使用JPQL实现太复杂了,因此我选择了本地查询。

存储库

@RepositoryRestResource(collectionResourceRel="projects", path="projects")
interface ProjectRepository extends BaseRepository<Project, Long>, ProjectRepositoryCustom {

    @Query(
        value="SELECT p.id, p.user_id, p.title, p.description, p.created_on, p.version,(SELECT COUNT(0) FROM projectparts WHERE project_id = p.id) AS parts,(SELECT COUNT(0) FROM requests WHERE project_id = p.id) AS requests FROM projects AS p ORDER BY ?#{#pageable}",
        countQuery="SELECT COUNT(0) FROM projects",
        nativeQuery=true
    )
    Page<Project> findAll(Pageable pageable)

}

该实体有2个属性被标注为@Transient,因此这些信息不会持久化到数据库。所有数据都返回正常,除了这2个瞬态属性,它们的值返回为null。当我从控制台复制查询并在MySQL Workbench中粘贴时,结果如预期所示,我可以看到需要的计数。无论如何,不确定是否还需要做其他工作才能使这个本地查询作为注释正常工作。我在子查询中硬编码了一个值 SELECT 55 FROM...,只是想查看计数是否有问题,但它仍然返回null。我在Workbench中运行查询,它正常工作。
我尝试更改瞬态属性类型,从Integer、Long、BigInteger、long、int...等类型,但没有任何区别。由于我正在使用Groovy,我还尝试了def来让Groovy推断类型,但也没用。
我还尝试从终端运行项目,但仍然没有显示计数结果。我已经在Mac和Linux上尝试过,都无法显示计数结果。
1个回答

3
这样做行不通。然而,你可以使用SQLConstructorExpression,但是返回的实例将是未经管理的,这是一个重大缺点。
更好的选择是创建一个简单的数据库视图,用于保存项目摘要信息的部分内容。你可以使用JPA的@SecondaryTable功能,将项目实体映射到其表和相关的摘要视图。

https://en.wikibooks.org/wiki/Java_Persistence/Tables#Example_mapping_annotations_for_an_entity_with_multiple_tables

另一个好处是您可以像对待任何其他属性一样对摘要值进行排序和查询。

更新的映射:

@Entity
@Table(name = "projects")
@SecondaryTable(name = "projects_summary_vw")
public class Project{

   //use Integer rather than int to avoid issue outlined here:
   //https://dev59.com/b5bfa4cB1Zd3GeqP0_Eq#37160701

    @Column(name  = "parts", table = "projects_summary_vw", 
          insertable="false", updateable="false")
    private Integer partsCount;

    @Column(name  = "requests", table = "requestsCount" 
          insertable="false", updateable="false")
    private Integer requestsCount;

    //other mappings as required
}

无需自定义查询:
@RepositoryRestResource(collectionResourceRel="projects", 
        path="projects")
interface ProjectRepository extends BaseRepository<Project, Long>, 
        ProjectRepositoryCustom {

}

如果不符合JPA标准,可以使用一些供应商特定的扩展来代替视图。例如,Hibernate有一个@Formula注释可以使用:

https://docs.jboss.org/hibernate/orm/5.1/javadocs/org/hibernate/annotations/Formula.html

@Entity
@Table(name = "projects")
public class Project{

    @Formula("my count query as native sql")
    private Integer partsCount;

    @Formula("my count query as native sql")
    private Integer requestsCount;

    //other mappings as required
}

谢谢您的反馈,我需要认真考虑这些选项。我几乎考虑过让JPA创建列,尽管我不会使用它们。 - Hatem Jaber
不要这样做。视图会很好地工作,并为您带来许多其他好处。 - Alan Hay
1
你是在谈论使用MySQL视图,并只使用@SecondaryTable将其他列映射到吗? - Hatem Jaber
是的,那就是方法。 - Alan Hay
谢谢Alan,我采用了@Formula方法,它完全按照我想要的方式工作。直到它达到1000并注意到它的积分,我才完全忘记它,想着我会将你的答案标记为正确答案,因为它确实是! - Hatem Jaber

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