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

Java 如何使用JPA和Hibernate连接两个不相关的实体,java,hibernate,jpa,join,entity,Java,Hibernate,Jpa,Join,Entity,我有两张桌子——一张是地址,另一张是照片。他们之间唯一的共同领域是人格。这些被映射到两个POJO类Address和Photo。通过创建条件并对字段添加限制,我能够获取这些表中的详细信息。我们应该如何在这两个表上编写联接。是否可以将结果作为两个对象—地址和照片 我想做一个左连接,这样我也可以得到没有照片的人的记录。 我读到只有使用hql才能做到这一点,但也可以使用criterias来实现吗?您正在寻找的是 HQL 在未建模为关系的字段上加入 左连接 在第一次提出这个问题并给出这个答案的时候,Hib

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

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

您正在寻找的是

HQL 在未建模为关系的字段上加入 左连接 在第一次提出这个问题并给出这个答案的时候,Hibernate支持Theta连接,它允许您执行1和2。但是,只有内部联接可用于θ联接样式

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


另一个答案实际上提供了一个新的Hibernate特性的更新,该特性提供了这样的特性,您可以简单地参考

最好有一个包含您想要加入的类的类,以便将它们全部包含在一起。
但是,如果只是出于某些偶然的目的连接这些表,则可以使用条件并手动从每个表加载数据并将它们放在一起。是的,如果Address和Photo有两个独立的类和表,那么可以分别使用这些表的数据

您可以很容易地编写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[]数组列表。这个数组的第一个元素将包含一个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();

这应该适用于您的情况。

12年后,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();

我现在很想尝试新功能。

基本上,您有两个选择:

自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();
在Hibernate 5.1之前,只能使用θ样式的联接。但是,θ样式联接相当于等速联接,因此只能模拟内部联接,而不能模拟外部联接

 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 5.1中可以连接两个不相关的实体

例如:


谢谢你的例子,但我们可以做一个左加入…我已经尝试使用地址左加入照片,但出现以下错误。。。外部联接或完全联接后面必须跟路径表达式OK。我编辑了我的答案并添加了左连接示例。我认为这应该适合您。@dimas我们可以在左join中使用hql吗?是否可以更改本机SQL查询,以便在多张照片链接到地址时,每个地址都会生成一个照片列表?martin,请您详细说明一下。如何为此场景创建类?使用联接中的属性创建一个类。此类应绑定到一个数据库表,其名称保存实体之间的关系。在这里,让我们把它们称为address\u photo\u rel table。因此,当hibernate为类创建表时,也会创建此联接表。如果您不这样做,并且由于您在这里的实体地址和照片之间存在关系,hibernate最终将创建该表,但您无法控制该表,因为您没有该表的类。不知道为什么它被否决。事实上,答案是正确的,即使是基于这一点的公认答案,我也举了一个例子,只是因为在提供的关键信息中找到它是微不足道的。并给出了左连接要求later@Ismael我会重新措辞一下,但我不认为我所说的是不完整的:没有合适的方法使用HQL来实现OP所要求的。Theta join是他能得到的最接近的,但因为它没有做他所做的,我只是不想在上面举例。以前的版本有什么替代品吗。我正在使用hibernate-entitymanager-5.0.9,它为我提供了加入的预期路径!错误您可以使用θ样式的连接。如果我没有弄错的话,我认为这不是一个无关的实体。这些通过电话属性进行关联。你能提供实体类吗?
 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();
select objA from ObjectA objA   
JOIN ObjectB objB on objB.variable = objA.variable    
where objA.id = 1