如何使用JPA和Hibernate连接两个不相关的实体



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

我想做一个左加入,这样我就可以获得没有照片的人的记录。我读到过,这只使用hql是可能的,但这也可以使用criteria吗?

您可以使用Theta Join轻松编写HQL查询,该查询将以两个对象的形式返回结果(正如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[]数组列表表示每个提取的行。这个数组的第一个元素将包含一个obejct,第二个元素将是另一个。

编辑:

在左联接的情况下,我认为您需要使用本机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();

这应该适用于您的情况。

基本上,您有两个选项:

  1. 自从Hibernate 5.1以来,您可以对不相关的实体使用特别连接。

     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样式的联接等效于equjoin,因此只能模拟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();
    

12年后,Hibernate团队终于实现了这样一个功能

来自Hibernate文档:

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中的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();

我目前很想试试这个新功能。

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

例如:

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

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

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

您想要的是

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

(在第一次提出问题并给出答案的时间内) Hibernate支持Theta Join,它允许您执行1&2.但是,theta联接样式只能使用内部联接。

就我个人而言,我建议你建立适当的人际关系,所以你只需要1&3,这在HQL中得到了很好的支持。

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

最新更新