关于HQL多对多映射表的查询,这里有很多问题,但是我看了很多,还没看过。
我有两个表具有多对多关系,其中源表和目标表映射为实体,并在它们之间定义了@ManyToMany关系,通常建议对其进行配置。
扭曲之处在于,我试图在这些表上进行查询,以便可以在单个查询中获得源键和目标键的值。原因是为了提高性能,我们深入嵌套了层次结构数据,并通过香草Hibernate结果获得了数十个或数百个性能不佳的查询中的所有相关数据。相反,我打算一次获取所有数据并将其映射到代码中。
以下是示例类定义:
@Entity
public class This {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
protected Long id;
@Column
protected Long otherId;
@ManyToMany
@JoinTable(joinColumns = {@JoinColumn(name = "this_id")},
inverseJoinColumns = {@JoinColumn(name = "that_id")})
private List<That> thats;
// getters and setters
}
和
@Entity
public class That {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "name", unique = true)
private String name;
// getters and setters
}
HQL是这样的:
select t.id,t.thats from This t where t.otherId=13
这是生成的SQL:
select
this0_.id as col_0_0_,
. as col_1_0_,
that2_.id as id1_59_,
that2_.name as name2_59_
from
this this0_
inner join
this_thats thats1_
on this0_.id=thats1_.this_id
inner join
that that2_
on thats1_.that_id=that2_.id
where
this0_.other_id=13
如您所见,select
子句中的第二列是无效的,看起来好像正在尝试创建一列,但没有使用有效的列名或别名,并且令人惊讶地生成了一条SQL语句无效语法的执行失败。我已经逐步完成了SQL生成代码,并打开了跟踪日志记录,但无法弄清它正在尝试做什么或如何解决它。
如果我删除第二列,则此查询运行良好,并完全返回我要查找的数据。作为替代方案,我曾考虑在本机SQL中实现此功能,但我想避免这种情况,并尽可能使用HQL,以确保整个项目的其余部分保持一致。
我尝试的另一个选项是select t,t.thats ...
。这确实产生了一个有效的查询,但是在此示例中未显示,但它针对从This
实体急切获取的其他关系发出了更多查询,这也导致性能下降。我真的只需要从源表中获取单个键列。
真正返回查询所需数据的最小查询根本不必命中That
表,只需要在This
表和隐式,未映射的{{1 }}表是由JPA创建和管理的,但未映射到实体。我尝试将其映射到实体,以便可以对其进行查询,但是Hibernate在启动时抱怨该表被映射了两次。如果还有其他方法可以访问此表并直接对其进行查询,我将很乐意这样做。
这是与hibernate-jpa-2.1一起使用的,我知道它是旧版本,但这是生产中的旧系统。如果升级JPA版本会有所帮助,我会考虑,但如果可能的话,希望首先了解根本原因。
答案 0 :(得分:1)
在使用 spring 数据 jpa 时,只需在存储库上使用 findAll 即可获取列表
但是如果您想要 HQL 方法,请尝试以下方法
将以下方法添加到存储库
@Query("select new ThisThat(u.id, u.otherId,th.name), "
"from This u " +
"inner join this_thats l on l.this_id=u.id " +
"inner join that th on th.id=l.that.id " +
"where u.id=:id)
List<ThisAndThat> getThisAndThat(long id);
创建一个名为 ThisAndThat 的类,如下所示
class ThisAndThat{
long id;
long otherId;
String name;
.......
}
答案 1 :(得分:0)
我不熟悉休眠的旧版本,但是我会尝试替换
{@JoinColumn(name = "this_id")} by {@JoinColumn(name = "this.id")}
和
{@JoinColumn(name = "that_id")} by {@JoinColumn(name = "that.id")}
答案 2 :(得分:0)
再试一次:也许问题是,您无法将列表作为SQL select语句的单行结果获得。也许您不必选择第二列,因为
List<That> thats
由休眠自动填充。
答案 3 :(得分:0)
您所说的或试图做的没有意义。 t.thats
是一个集合,因此您不能将其作为一行的一部分返回。您需要考虑使用JPA面向更多对象。而且,JPA 2.1并不是特别过时,因此那里应该没有问题。因此,一个可以预取thats
集合的工作查询是这样完成的:
This t2 = em.createQuery("from This t left outer join fetch t.thats where t.otherId = 12", This.class).getSingleResult();
System.out.println("" + t2 + t2.getThats());
此查询告诉JPA在单个查询中获取所需的This
和任何相关的thats
。
您声明只需要ThisThat
连接表的内容。该表仅具有关系的ids
。出于某些原因,您可能需要id,以便稍后进行thats
的提取。足够公平,但是就像您说的那样,您必须将连接表创建为单独的实体,然后使用仅joins
仅该实体的查询。很有可能,但这也是一个单独的问题,您应该首先尝试更多操作。
为完整起见,您已为unidirectional
实体拥有的This
ManyToMany映射建模。
答案 4 :(得分:0)
我想出了答案,我正在发布该答案以帮助遇到此问题的任何其他人。 join
必须在HQL中明确显示,如下所示:
select t.id,th from This t join t.thats th where t.otherId=13
显然,没有这个,Hibernate无法找出正确的选择语句。