带有连接的休眠自定义 SQL 查询 - 避免返回数组列表

Posted

技术标签:

【中文标题】带有连接的休眠自定义 SQL 查询 - 避免返回数组列表【英文标题】:Hibernate custom SQL query with join - avoiding returning a list of arrays 【发布时间】:2010-06-25 11:42:45 【问题描述】:

我在 Hibernate (3.5.2) 中有一个自定义 SQL 查询,我想在其中返回一个映射对象和一个关联(连接)对象。然而,Hibernate 似乎给了我一个数组列表而不是一个对象列表。

为了简化我的情况:-

Entity1 包含一个指向 Entity2 的外键,并且设置了映射对象,以便 Entity1 具有引用 Entity2 的对象属性。我想检索 Entity1 对象的列表,但关联的对象引用已经初始化(以便已加载关联的对象)。

现在,我可以使用这样的自定义 SQL 查询来做到这一点:

final SQLQuery qry = hibernateSession.createSQLQuery(
    "select entity1.*, entity2.* from entity1 inner join entity2 on entity1.fk = entity2.id ");

qry.setReadOnly(true);
qry.addEntity("entity1", Entity1.class);
qry.addJoin("entity2", "entity1.entity2");

List list = qry.list();  // Returns list of arrays!!

这是可行的,因为所有 Entity1 对象都已正确初始化。但是,我返回的列表不是 Entity1 对象的简单列表。它实际上是一个数组列表,其中每个数组包含 2 个元素 - Entity1 和 Entity2。我假设这是因为我在 SELECT 子句中放置了两个别名条目。

如果我删除第二个别名(对于 Entity2),我只会收到“未找到列”错误 - 大概是因为 Hibernate 找不到用于初始化 entity2 的字段。

有什么想法吗?我有一个查询可以返回主要和关联对象的字段,但我希望返回的列表只是 Entity1 对象的列表。

先发制人的评论:是的,我知道我可能会重新构建它并以不同的方式进行查询(标准 API 等)。但这就是我目前所坚持的。在这种特殊情况下,我受到其他一些因素的限制,所以希望有某种方式可以告诉 Hibernate 我想要什么!

谢谢。

【问题讨论】:

您是特别想用原生 SQL 查询来做这件事,还是 HQL 会做? 您可以使用 HQL 对未映射的关系进行内部连接,如下所示:select * from Entity1 e1, Entity2 e2 where e1.fk = e2.id。 This sadly does not work for outer joins. 这在 HQL 中很容易,您的查询中有什么是 HQL 无法完成的? 我遇到了完全相同的问题 - 我发现了这个错误单,它描述了相同的问题 hibernate.atlassian.net/browse/HHH-2831 但它已被关闭而没有修复 【参考方案1】:

这里实体 1(子)包含实体 2(父)的外键,在 Entity1(子)类的 pojo 中应该有一个父类型变量。 让这是'E'现在查询将是:

Select ent1.* from Entity1 ent1 inner join ent1.E.id

这里id是Entity2的主键

【讨论】:

【参考方案2】:

我面前没有hibernate来测试,看hibernate手册好像暗示了这个小改动:

final SQLQuery qry = hibernateSession.createSQLQuery(
    "select entity1.* from Entity1Table entity1 inner join Entity2Table entity2 on entity1.fk = entity2.id ");

qry.setReadOnly(true);
qry.addEntity("entity1", Entity1.class);
qry.addJoin("entity1.entity2");  

这应该只返回 Entity1 对象,而 Entity2 属性已经初始化。

如果这不起作用,那么尝试用 where 子句替换 SQL 中的内连接,即

select entity1.* from Entity1Table entity1, Entity2Table entity2 WHERE entity1.fk = entity2.id ");

这在语法上等同于 hibernate 文档中给出的示例。

【讨论】:

更改连接语法不起作用。从 select 子句中删除 entity2 的列只会导致 Hibernate 抛出“找不到列”错误。 感谢您的尝试。我很困惑——据我所见,它应该与返回“cat”和“dog”属性的休眠文本中的本机 SQL 示例完全相同。 注意!某些数据库默认使用交叉连接(例如 postgresql) CROSS JOIN 子句产生两个或多个表中行的笛卡尔积。使用 ", " 与 INNER JOIN 不同【参考方案3】:

看看this能不能帮到你……

【讨论】:

【参考方案4】:

一种方法是使用 Theta-Style 连接:

select u from User u join u.permissions p where p.code = :code; 

Permissions 是映射到用户类的集合。

【讨论】:

【参考方案5】:

我认为你想要的是一个 fetch 连接。这是一个将列从数据库中返回的连接,这些列被转换为对象,但这些对象仅添加到会话缓存中,而不是在结果中返回。

通过 JPA、旧版 Hibernate API、旧版标准 API 等有不同的方法。

如果您使用的是本机 SQL,您应该可以通过调用 SQLQuery::addFetch 来实现,将您对 addJoin 的调用替换为:

qry.addFetch("entity2", "entity1", "fk");

或者类似的东西。我不得不承认我并不真正理解这些参数的含义,而且我通过一些快速搜索也找不到任何好的文档。

【讨论】:

addFetch 从 Hibernate 3.6 开始。问题是针对 Hibernate 3.5.2。 @xmedeko:你说得对,很好。我看不到使用 Hibernate 3.5 对 SQLQuery 进行纯 fetch join 的方法。 这不起作用。 addFetchaddJoin 的一个更可定制的变体(但基本相同),因为它返回FetchReturn 而不是void。遗憾的是,FetchReturn 不包含关闭连接显式返回的选项。

以上是关于带有连接的休眠自定义 SQL 查询 - 避免返回数组列表的主要内容,如果未能解决你的问题,请参考以下文章

带有外连接的休眠 HQL 查询

使用带有休眠 SQL 查询的多列的参数化 IN 子句

错题纠正

优化返回大量记录的查询,避免数百个连接。这是一个聪明的解决方案吗?

带有自定义比较器的 Linq 左外连接

错题集07