使用的Hibernate版本:
<artifactId>hibernate-annotations</artifactId>
<version>3.5.5-Final</version>
<artifactId>hibernate-core</artifactId>
<version>3.5.5-Final</version>
<artifactId>hibernate-commons-annotations</artifactId>
<version>3.2.0.Final</version>
<artifactId>hibernate-jpa-2.0-api</artifactId>
<version>1.0.0.Final</version>
假设有两只猫(猫和它的伴侣有相同的小猫) cat / cat的伴侣与它的小猫有一个关系,小猫的名字作为连接列(连接列上的OneToMany关系,获取类型为“eager”)
假设我想让小猫的名字“大”的猫,我可以用不同的方式编写hql。
I.
hql.append("from Cat as cat ")
hql.append("where cat.kitten.name = 'big' ");
II.
hql.append("from Cat as cat inner join cat.kitten as kitten ")
hql.append("where kitten.name = 'big' ");
前面提到的hql在cat和它的小猫之间产生了一个内部联接,并且按预期工作。
但是,如果我想在小猫的某个属性上查询哪个猫没有加入小猫(比如说位置),我可以按如下方式编写hql:
III.
hql.append("from Cat as cat ")
hql.append("where cat.kitten.location = 'Chicago' ");
IV.
hql.append("from Cat as cat inner join cat.kitten as kitten ")
hql.append("where kitten.location = 'Chicago' ");
问题1)III和IV也正如预期的那样工作,但是,III在cat和它的小猫之间产生了笛卡尔/交叉连接而没有在hql中提到的显式连接,而IV则不是。那是为什么?
和
说,我想加入两个“不同”的对象cat和mate in hql(没有任何关联)在mate的名字上,它正在生成交叉连接。
例如,如果我说,
V.
hql.append("select cat ")
hql.append("from Cat as cat, Mate mate ")
hql.append("where cat.location = mate.location and mate.location = 'Chicago' ");
它会生成交叉连接。
但是,如果我说,
VI.
hql.append("from Cat as cat ")
hql.append("where cat.location in ( select mate.location from Mate mate where mate.location = 'Chicago' ");
问题2)它不会生成交叉连接。但是,如果我必须使用两列,该怎么办呢?我需要使用两个in子句来没有hql生成的交叉连接。为什么必须明确?或者是否有一个休眠配置来说明如果可能,请避免交叉连接?
答案 0 :(得分:0)
在第一种形式(I,III,V)中,表之间的连接条件在映射中定义(可能在<one-to-many>
,<many-to.one>
,<one-to-one>
或{{1子句)。在例子中我似乎已经定义了一个正确的,在III和V中你没有正确地做到这一点。
在示例II,IV和VI中,您已明确定义了连接(或子选择)。如果HQL语句中存在连接,则Hibernate总是在单个SQL语句中使用此连接(如果在映射中定义了连接,则不是这种情况 - Hibernate通常更喜欢两个独立选择(延迟加载仅适用于此)) 。如果a)映射中的表之间没有连接,并且您需要第二个表用于where条件,或者b)出于性能原因要强制hibernate直接连接到一个语句而不是使用两个不同的语句时,这很有用
如果我们告诉你为什么III和V不起作用并产生笛卡尔积,那么你必须给我们表格的映射。