如何使用 Hibernate 将 SQL 查询的结果最好地映射到非实体 Java 对象?

Posted

技术标签:

【中文标题】如何使用 Hibernate 将 SQL 查询的结果最好地映射到非实体 Java 对象?【英文标题】:How to best map results from an SQL query to a non-entity Java object using Hibernate? 【发布时间】:2012-08-04 21:04:09 【问题描述】:

我有一个名为 X 的 Hibernate 托管 Java 实体和一个本机 SQL 函数 (myfunc),我从 Hibernate SQL 查询中调用这些函数:

SQLQuery q = hibernateSession.createSQLQuery(
                     "SELECT *, myfunc(:param) as result from X_table_name"
             );

我想要做的是将这个查询返回的所有内容映射到一个名为 Y 的类(不一定由 Hibernate 管理)。Y 应该包含来自 X 的所有属性/字段加上 myfunc 返回的 result,例如Y 可以扩展类 X 并添加一个“结果”字段。

我尝试过的:

    我试过使用q.addEntity(Y.class),但失败了: org.hibernate.MappingException: Unknown entity com.mycompany.Y q.setResultTransformer(Transformers.aliasToBean(Y.class)); 但这失败了:org.hibernate.PropertyNotFoundException: Could not find setter for some_property。 X 有一个名为 someProperty 的字段,带有适当的 getter 和 setter,但在这种情况下,Hibernate 似乎没有将列名 (some_property) 映射到正确的字段名。 q.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP); 返回一个 Map,但值并不总是 X 中相应字段所期望的类型。例如,X 中类型为 enum 和 Date 的字段不能直接从 SQL 查询返回的 Map 映射(它们是字符串)。

处理这种情况的适当方法是什么?

【问题讨论】:

【参考方案1】:

请参阅chapter of the documentation about SQL queries。

您可以使用addScalar() 方法来指定Hibernat 应为给定列使用的类型。

您可以使用别名来映射结果与 bean 属性:

select t.some_property as someProperty, ..., myfunc(:param) as result from X_table_name t

或者,(虽然它需要一些代码行,但这是我的首选解决方案),您可以简单地自己进行映射:

List<Object[]> rows = query.list();
for (Object[] row : rows) 
    Foo foo = new Foo((Long) row[0], (String) row[1], ...);

这样可以避免反射,让您控制一切。

【讨论】:

Eek,投给Long。您如何提前知道row[0] 将成为Long?有没有办法通过 Hibernate API 强制数据类型转换? @LukasEder:点击文档链接,那里有解释。但是在 Hibernate 中使用 SQL 查询应该是非常特殊的。大多数时候,您使用 HQL/条件查询,类型是从实体中的字段类型推断出来的。 感谢您的信息。我应该已经完全阅读了您的答案...尽管如此,必须重复类型信息仍然有点痛苦【参考方案2】:

首先你需要在hibernate配置xml文件中声明实体,如下所示:..... class="实体路径"

或者您可以在进行查询之前以编程方式执行相同的操作。

【讨论】:

【参考方案3】:

简单。将行转换为Map&lt;String, Object&gt;

final org.hibernate.Query q = session.createSQLQuery(sql);
q.setParameter("geo", geo);
q.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
final List<Map<String, Object>> src = q.list();
final List<VideoEntry> results = new ArrayList<VideoEntry>(src.size());
for (final Map<String, Object> map:src) 
    final VideoEntry entry = new VideoEntry();
    BeanUtils.populate(entry, map);
    results.add(entry);

【讨论】:

好主意,但仅当数据库列的命名与实体字段完全相同时才有效。

以上是关于如何使用 Hibernate 将 SQL 查询的结果最好地映射到非实体 Java 对象?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Hibernate 将 SQL 查询的结果最好地映射到非实体 Java 对象?

Hibernate...如何进行数据库/SQL 查询?

笔记:Hibernate SQL 查询

如何计算使用 Hibernate 对 H2 数据库进行的 SQL 查询的数量

如何修改hibernate生成的SQL查询?

hibernate使用setResultTransformer()将SQL查询结果放入集合中