【问题标题】:How to join two unrelated entities using JPA and Hibernate如何使用 JPA 和 Hibernate 连接两个不相关的实体
【发布时间】:2012-08-03 01:42:28
【问题描述】:

我有两张表格 - 一张包含地址,另一张包含照片。它们之间唯一的共同字段是 PersonID。这些被映射到两个 POJO 类地址和照片。我能够通过创建条件和对字段添加限制来获取这些表中的详细信息。我们应该如何在两个表上编写连接。是否可以将结果作为两个对象 - 地址和照片。

我想做一个左连接,这样我也可以得到没有照片的人的记录。 我已经读到这只能使用 hql 才能实现,但这也可以使用标准来完成吗?

【问题讨论】:

    标签: java hibernate jpa join entity


    【解决方案1】:

    基本上,您有两种选择:

    1. 从 Hibernate 5.1 开始,您可以将ad-hoc joins 用于不相关的实体。

       Tuple postViewCount = entityManager.createQuery(
           "select p as post, count(pv) as page_views " +
           "from Post p " +
           "left join PageView pv on p.slug = pv.slug " +
           "where p.title = :title " +
           "group by p", Tuple.class)
       .setParameter("title", "High-Performance Java Persistence")
       .getSingleResult();
      
    2. 在 Hibernate 5.1 之前,您只能使用 theta 样式的连接。但是,theta 样式的连接等同于等值连接,因此您只能模拟 INNER JOIN 而不是 OUTER JOIN。

       List<Tuple> postViewCount = entityManager.createQuery(
           "select p as post, count(pv) as page_views " +
           "from Post p, PageView pv " +
           "where p.title = :title and " +
           "      ( p.slug = pv.slug ) " +
           "group by p", Tuple.class)
       .setParameter("title", "Presentations")
       .getResultList();
      

    【讨论】:

    • 以前的版本有没有替代品。我正在使用 hibernate-entitymanager-5.0.9 这给了我“加入的预期路径!”错误
    • 你可以使用theta风格的连接。
    【解决方案2】:

    您可以轻松编写 HQL 查询,该查询将使用 Theta Join 将结果作为两个对象返回(如 Adrian 所述)。这是一个例子:

    String queryText = "select address, photo from Address address, Photo photo " 
                     + " where address.personID=photo.personId";
    List<Object[]> rows = session.createQuery(queryText).list();
    
    for (Object[] row: rows) {
        System.out.println(" ------- ");
        System.out.println("Address object: " + row[0]);
        System.out.println("Photo object: " + row[1]);
    }
    

    如您所见,查询返回代表每个提取行的 Object[] 数组列表。该数组的第一个元素将包含一个对象和第二个元素 - 另一个。

    编辑:

    如果是左连接,我认为您需要使用本机 SQL 查询(而不是 HQL 查询)。在这里你可以如何做到这一点:

    String queryText = "select address.*, photo.* from ADDRESS address 
                        left join PHOTO photo on (address.person_id=photo.person_id)";
    
    List<Object[]> rows = sess.createSQLQuery(queryText)
                              .addEntity("address", Address.class)
                              .addEntity("photo", Photo.class)
                              .list();
    

    这应该适用于您的情况。

    【讨论】:

    • 感谢您的示例,但我们可以进行左连接吗...我尝试使用“地址左连接照片”,但出现以下错误...“外部或完全连接必须后跟路径表达”
    • 好的。我编辑了我的答案并添加了左连接的示例。我认为这应该适合你。
    • @dimas 我们可以在左连接中使用 hql
    • 是否可以改变原生 SQL 查询,以便在多张照片链接到地址时生成每个地址的照片列表?
    【解决方案3】:

    在 Hibernate 5.1 中可以连接两个不相关的实体。

    例如:

    select objA from ObjectA objA   
    JOIN ObjectB objB on objB.variable = objA.variable    
    where objA.id = 1
    

    【讨论】:

      【解决方案4】:

      你要找的是

      1. HQL
      2. 加入尚未建模为关系的字段
      3. 左连接

      (在第一次提出问题并给出此答案期间) Hibernate 支持 Theta Join,它允许您执行 1 和 2。但是,只有内部连接可用于 theta 连接样式。

      我个人建议您对适当的关系建模,因此您只需要在 HQL 中得到很好支持的 1 和 3。

      (另一个答案实际上提供了有关提供此类功能的新 Hibernate 功能的更新,您可以简单地参考)

      【讨论】:

      • 想知道为什么它被否决了。答案实际上是正确的(即使是基于此的公认答案),我确实给出了示例,只是因为在提供的关键信息中找到它是微不足道的。而left join的要求在后面给出
      • @Ismael 我会改写一下,但我认为我所说的并不完整:没有正确的方法使用 HQL 来实现 OP 的要求。 Theta join 是他能得到的最接近的加入,但由于它没有做他做什么,我只是不会费心举例说明。
      【解决方案5】:

      Hibernate 团队 12 年后终于有了implemented such a feature

      来自Hibernate docs

      FROM 子句还可以包含使用 join 关键字的显式关系连接。这些连接可以是内连接或左外连接。

      List<Person> persons = entityManager.createQuery(
          "select distinct pr " +
          "from Person pr " +
          "join pr.phones ph " +
          "where ph.type = :phoneType", Person.class )
      .setParameter( "phoneType", PhoneType.MOBILE )
      .getResultList();
      
      
      List<Person> persons = entityManager.createQuery(
          "select distinct pr " +
          "from Person pr " +
          "left join pr.phones ph " +
          "where ph is null " +
          "   or ph.type = :phoneType", Person.class )
      .setParameter( "phoneType", PhoneType.LAND_LINE )
      .getResultList();
      

      或者您可以使用WITHON 关键字。对这些的评论

      重要的区别在于生成的 SQL 中的条件 WITH/ON 子句的一部分成为生成的 ON 子句的一部分 SQL,与本节中的其他查询相反,其中 HQL/JPQL 条件是生成的 WHERE 子句的一部分 SQL。

      例子

      List<Object[]> personsAndPhones = session.createQuery(
          "select pr.name, ph.number " +
          "from Person pr " +
          "left join pr.phones ph with ph.type = :phoneType " )
      .setParameter( "phoneType", PhoneType.LAND_LINE )
      .list();
      

      我目前渴望尝试新功能。

      【讨论】:

      • 如果我没记错的话,我想这不是unrelated entity。这些通过phones 属性关联。能否提供实体类?
      【解决方案6】:

      最好有一个包含您想加入的课程的课程,以便将它们放在一起。

      但是,如果您只是出于某些偶然目的而加入这些表,则可以使用条件并手动从每个表中加载数据并将它们放在一起。 (是的,如果 Address 和 Photo 有两个单独的类和表,您可以分别拥有这些表的数据)

      【讨论】:

      • 马丁你能详细说明一下吗。如何为这种情况创建一个类?
      • 使用您在加入时拥有的属性创建一个类。此类应绑定到具有保存实体之间关系的名称的数据库表。 (这里我们称他们为address_photo_rel 表)。因此,当 hibernate 为您的类创建表时,也会创建此连接表。 如果您不这样做,并且由于您的实体之间存在关系(此处为 addressphoto),休眠将最终创建该表,但您无法控制它,因为您没有为它上一堂课。
      猜你喜欢
      • 2013-06-10
      • 2012-07-12
      • 1970-01-01
      • 2012-04-12
      • 1970-01-01
      • 2017-06-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多