Hibernate/JPA:是否可能在单个查询中检索异构实体?

3
我有两个实体:EntityA和EntityB。
它们没有关联,由于某些限制,我无法将它们放入继承树中。
但是我需要在同一个JPQL或HQL查询中获得一个混合列表,其中包含这两个实体的所有实例。JPA或甚至Hibernate可以直接实现吗?
我需要像这样的结果:
FROM EntityA WHERE fieldA=1
UNION
FROM EntityB WHERE fieldB="aa"

有任何提示吗?

1
简单的方法是制作两个查询并将两个列表连接在一起,形成一个“List<Object>”。 - toto2
谢谢,但正如我所评论的,我被迫在一个查询中同时执行两个操作,因为我正在使用分页,而且我无法对独立的查询进行分页。 - Mr.Eddart
如果您使用HQL进行分页,它仍然无法工作:请参阅Hibernate参考文档 - dma_k
2个回答

5

我终于明白了。

只需让实体类实现一个共同的接口即可(甚至不需要在Hibernate中声明此接口)。

然后,可以执行如下查询:

FROM my.package.CommonInterface obj
WHERE obj IN (FROM EntityA WHERE fieldA=1) OR
      obj IN (FROM EntityB WHERE fieldB='a')

这样,您会检索到一个List<CommonInterface>
问题解决了。

对于您的第一个问题,Hibernate返回CommonInterface的实例,其中一些将是EntityA的实例,另一些将是EntityB的实例。至于您的第二个问题,我不知道生成的SQL(这在此时并不让我担心)。 - Mr.Eddart
我快速查看了生成的SQL。它不是最优的,因为Hibernate生成了2个查询:SELECT EntityA.* WHERE id IN (SELECT EntityA.id ... WHERE fieldA=1) OR id IN (SELECT EntityB.id ... WHERE fieldB='a')SELECT EntityB.* WHERE id IN (SELECT EntityB.id ... WHERE fieldB='a') OR id IN (SELECT EntityA.id ... WHERE fieldA=1)。显然,每个查询中的第二个子查询是错误的(至少在我的情况下)。在Hibernate文档中没有太多关于此的信息 :( - dma_k
在寻找资料后,我得出结论:只有当 EntityAEntityB 都拥有相同的映射属性 fieldX (很可能在通用接口 CommonInterface.getFieldX 中声明了一个 getter)时,才能实现最优化的 SQL。因此,查询 FROM my.package.CommonInterface obj WHERE obj.fieldX = 1 将会生成两个 SQL 查询,但它们将是最优化的。 - dma_k
是的,你说得对,每个实体都执行了2个查询,我会说Hibernate的这种行为完全是错误的!我甚至会说这是一个BUG,因为如果你尝试对查询结果进行排序,它根本不起作用,它只是将ORDER BY独立地应用于每个SQL查询,而不是应用于整个集合。完全搞砸了,我想想解决方法,因为现在对我来说是个问题。 - Mr.Eddart
我错了,使用UNION不可能因为数据类型的不同,但是Hibernate应该保持HQL语言的语义即使需要在内存中进行处理... - Mr.Eddart
显示剩余4条评论

2

最好的方法是执行两个查询。

但是如果你必须这样做:

您可以创建一个POJO来检索它们:

class EntityAandEntityB {
    EntityA a;
    EntityB b;
    long idA;
    long idB;
    int fieldA;
    String fieldB;

    public EntityAandEntityB(long idA, long IdB, int fieldA, String fieldB) {
       this.a = new EntityA(idA, fieldA);
       this.b = new EntityB(idB, fieldB);
    }
}

那么您的查询将是:
select new package.EntityAandEntityB(a.idA, a.fieldA, b.idB, b.fieldB) from ( 
    (select idA, fieldA from EntityA) a
UNION
    (select idB, fieldB from EntityB) b)

这很混乱,你可能需要仔细查看语法。

谢谢。


你能否提供Hibernate从你提供的HQL生成的SQL查询语句? - dma_k
感谢您提供的解决方案:在阅读对应的Hibernate章节时,我学到了很多。查询结果是否可以使用scroll()方法滚动显示?我猜不行... - dma_k

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接