如何通过单个查询选择不相关的实体

时间:2018-07-13 11:41:12

标签: sql-server hibernate spring-data-jpa jpql

让我们想象一下,我们有5个表,彼此之间没有关系,但是它们共享同一列。我们将表命名为ClojureConfKotlinConfScalaConfGroovyConfJavaConf。它们都有一列UserId。其他各列的数量和数据类型各不相同。给定的用户可能参加了零个或多个会议。

任务是从给定的UserId的5个表中的每个表中选择所有记录,将它们转换为DTO并以json的形式返回。

当前,代码执行5次访问数据库的操作,以获取每个表的结果列表。

hibernate / jpa中是否有库支持,一次访问数据库的原因是什么?目标是提高性能。

是否可以为看起来与此相似的实体定义投影:

interface ConfAttended {

    List<ClojureConf> getClojureConfs();
    List<KotlinConf> getKotlinConfs();
    List<ScalaConf> getScalaConfs();
    List<GroovyConf> getGroovyConfs();
    List<JavaConf> getJavaConfs();

}

和一个可以一次性选择和映射结果的存储库

interface ConfAttendedDAO extends JpaRepository<User, Long> {

    @Query("SELECT c, k, s, g, j FROM ClojureConf c " +
            "JOIN KotlinConf k ON c.UserId = k.UserId " +
            "JOIN ScalaConf s ON c.UserId = s.UserId " +
            "JOIN GroovyConf g ON c.UserId = g.UserId " +
            "JOIN JavaConf j ON c.UserId = j.UserId " +
            "WHERE c.UserId = :userId")
    ConfAttended findByUserIdForProjection(@Param("userId") long userId);

}

1 个答案:

答案 0 :(得分:2)

我最终遇到了这样的查询:

interface ConfAttendedDAO extends JpaRepository<User, Long> {

    @Query("SELECT c, k, s, g, j FROM User u " +
            "LEFT JOIN ClojureConf c ON c.UserId = :userId " +
            "LEFT JOIN KotlinConf k ON k.UserId = :userId " +
            "LEFT JOIN ScalaConf s ON s.UserId = :userId " +
            "LEFT JOIN GroovyConf g ON g.UserId = :userId " +
            "LEFT JOIN JavaConf j ON j.UserId = :userId " +
            "WHERE u.Id = :userId")
    List<Object[]> findAllByUserId(@Param("userId") long userId);

}

Hibernate负责将行映射到实体。每个Object[]都具有全部5个实体(或null)作为其元素。从User中进行选择将强制查询返回结果。否则,如果第一个表什么都不返回-整个查询什么也不返回。另一个缺点是,如果一个表有10个结果,而另一个表有1个,则结果较少的表会使它们重复。

关于性能(这样做的唯一目的),获得和处理结果的速度比5个单独的SELECT快4-5倍。