【问题标题】:UNION to JPA QueryUNION 到 JPA 查询
【发布时间】:2013-09-28 07:28:59
【问题描述】:

是否可以在 JPA 甚至“Criteria Builder”中查询“UNION”?

我正在寻找示例,但到目前为止我没有得到任何结果。

有没有人有例子说明如何使用它?

还是使用原生 sql?

【问题讨论】:

标签: java jpa criteria


【解决方案1】:

SQL 支持 UNION,但 JPA 2.0 JPQL 不支持。大多数联合都可以通过连接来完成,但有些不能,有些则更难以使用连接来表达。

EclipseLink 支持 UNION。

【讨论】:

【解决方案2】:

根据具体情况,可以使用子查询,例如:

select e
from Entity e
where e.id in
(
  select e.id
  from Entity2 e2
       join e2.entity e
  where e2.someProperty = 'value'
)
      or e.id in
(
  select e.id
  from Entity3 e3
       join e3.entity e
  where e3.someProperty = 'value2'
)

【讨论】:

  • 子查询超过1000条结果如何处理?
  • 对于 MS SQL,它实际上超过 2000,这并不能改变它无法工作的事实。您可以获取所有这些 id,然后按您要设置的限制对结果列表进行分区,然后对所有子列表执行查询并连接结果。考虑到 JPA 的工作方式,这还不错,但与往常一样,这取决于您的用例。
  • 甚至没有提到 UNION 的某些用法是为了避免 OR(在调整 SQL 性能时)。我个人有一个非常慢的 OR 子表达式。重写以使用联合后,它变得更快。现在我必须找到一个解决方案来使用 CriteriaBuilder 构建它:(
  • 这个“或”解决方案可能会导致不幸地阻止某些索引的使用
  • 超过 1000 个值(可配置)的问题不适用于 Oracle 中的子查询。仅在使用参数时发生。
【解决方案3】:

我突然想到一件事(搜索完全相同的问题):

对同一个实体映射执行两个不同的 JPA 查询,只需将第二个结果的对象添加到第一个结果的列表(或设置以避免重复)。

这样可以获得与使用 UNION 相同的效果,不同之处在于您使用两个 SQL 语句而不是一个。但实际上,我希望它的性能与发出一条 UNION 语句一样好。

【讨论】:

  • 天才!!!在 JPQL 支持工会之前应该被认为是最佳答案
  • 嗯,这是显而易见的解决方法之一,但我也想将结果全部排序,例如,我更喜欢在 sql 中而不是在 java 中这样做
  • 但这不是问题,kopelitsa,您可以随时使用 SQL 并制作视图。
  • 我不同意。 @Giovane 询问是否可以在 JPA 中执行 UNIONS,并且可以在 SQL 视图中完成 UNION 的事实是无关紧要的。并非所有 JPA 用例都可以要求数据库所有者在其数据库中创建视图。
  • 但是我们不能进行分页。
【解决方案4】:

编写本机查询(设置为 true,默认为 false)- 例如。

String findQuery = "select xyz from abc union select abc from def"
@Query(value = findQuery, nativeQuery = true)
//method

【讨论】:

    【解决方案5】:

    使用 EntityManager.createNativeQuery(...); 它允许你使用 UNION

    【讨论】:

    • 没错,我不知道为什么这被否决了,但这是一个非常有效的选择,尤其是在性能方面。
    • @Motolola 也许是因为答案是关于 JPA 而不是原生查询?
    【解决方案6】:

    JPA 没有直接联合,我做的是建立两个规范。

    Specification<Task> specification = Specification.where(null);
    Specification<Task> specification2 = Specification.where(null;
    

    它们属于一个表,但返回不同的值

    specification = specification.and((root, criteriaQuery, criteriaBuilder) -> criteriaBuilder.equal(criteriaBuilder.function(MONTH, Integer.class, root.get("deliveryExpirationDate")), month));
            specification2 = specification2.and((root, criteriaQuery, criteriaBuilder) -> criteriaBuilder.lessThan(criteriaBuilder.function(MONTH, Integer.class, root.get("deliveryExpirationDate")), month))
                .and((root, criteriaQuery, criteriaBuilder) -> criteriaBuilder.equal(root.get("enable"), true));
    

    对于这个例子,它是一个任务表,在第一个规范中我需要启用和禁用当月的任务,而在第二个规范中我只需要启用前几个月的任务。

    Specification<Task> specificationFullJoin = Specification.where(specification).or(specification2);
    

    Esto es muy útil para que la lista de tareas devueltas tenga paginación.

    taskRepository.findAll(specificationFullJoin, pageable).map(TaskResponse::new); //Here you can continue adding filters, sort or search.
    

    它对我帮助很大,我希望这是他们正在寻找的东西,或者它为他们服务。

    【讨论】:

      【解决方案7】:

      您可以在查询中直接使用 UNION。 以下查询返回 FRIENDSHIP 表中好友的 id。

      例如:

      TypedQuery<String> queryFriend = em.createQuery("SELECT f.Id FROM Friendship f WHERE f.frStuId = :stuId UNION "
                                       + "SELECT f.frStuId FROM Friendship f WHERE f.FriendId = :stuId", String.class);
      queryFriend.setParameter("stuId", stuId);
      
      List<String> futureFriends = queryFriend.getResultList();
      

      【讨论】:

      • 呃,不。正如所有答案都告诉你的那样,JPQL 没有“UNION”。 JPA 提供者接受的唯一方法是提供 VENDOR EXTENSION。 OP 是否说过使用什么 JPA 提供程序?没有。
      猜你喜欢
      • 2017-10-29
      • 2012-08-11
      • 1970-01-01
      • 2019-03-02
      • 2017-06-05
      • 2011-04-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多