如何使用单个查询选择不相关的实体

Posted

技术标签:

【中文标题】如何使用单个查询选择不相关的实体【英文标题】:How to select unrelated entities with a single query 【发布时间】:2018-12-21 18:53:24 【问题描述】:

假设我们有 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);


?

【问题讨论】:

如果您想从 5 个表中获取 5 条单条记录,并将它们全部检索为一行 - 您需要做的就是使用 JOIN 或 CROSS APPLY ,或 LEFT join 或 OUTER APPLY。你可以在选择的条件下加入 - 你的问题似乎有这个 我想调查可能的选项。对于给定的UserId,一个表中可能有 0 条记录,而另一个表中可能有 10 条记录。是否可以编写一个 SELECT 来连接所有表中的所有列并用空值或重复值填充缺失? JPQL 不允许对不相关的实体使用“JOIN”语法。 有没有办法为不相关的实体发出批量SELECT? 【参考方案1】:

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

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 个实体(或空值)作为其元素。从User 中选择是强制查询返回结果。否则,如果第一个表不返回任何内容 - 整个查询不返回任何内容。另一个缺点是,如果一个表有 10 个结果而另一个有 1 个结果,则结果较少的表会使它们重复。

至于性能(做这一切的唯一目的),获取和处理结果比使用 5 个单独的SELECTs 快 4-5 倍。

【讨论】:

你使用的是哪个版本的休眠?

以上是关于如何使用单个查询选择不相关的实体的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 JPA Criteria API 连接不相关的实体

如何编写基于组合框选择的单个 sql 查询?

如何使用多个 XPath 查询在 c# 中选择单个 XML 节点

将多个表动态映射到单个实体

如何按包含的实体搜索/选择,但将所有相关实体包含到结果集中

如何使用 Hibernate 加载实体列表和这些实体相关实体的子集?