基本上我想要加载属性。我有以下HQL查询:
SELECT u.id AS id, u.name AS text, u AS obj FROM User AS u fetch all properties
我希望这只能执行一个查询。相反,我得到了N + 1个查询。
代码如下:
Query q = mySession.createQuery(
"SELECT u.id AS id, u.name AS text, u AS obj FROM User AS u fetch all properties")
.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
for (Iterator i = q.iterate(); i.hasNext();) {
Object line = i.next();
System.out.println(line);
}
我得到的输出(hibernate.show_sql
设置为true
)是:
Hibernate: select user0_.id as col_0_0_, user0_.name as col_1_0_, user0_.id as col_2_0_ from user user0_
Hibernate: select user0_.id as id0_0_, user0_.name as name0_0_, user0_.location as location0_0_ from user user0_ where user0_.id=?
{id=1, obj=User@b6548 [id='1' name='John' ], text=John}
Hibernate: select user0_.id as id0_0_, user0_.name as name0_0_, user0_.location as location0_0_ from user user0_ where user0_.id=?
{id=2, obj=User@4865ce [id='2' name='Arnold' ], text=Arnold}
Ps:没有变形金刚,情况就是一样。
包含entity-mappings的文件:
<hibernate-mapping>
<class name="User" table="user">
<id name="id" column="id">
<generator class="native"/>
</id>
<property name="name"/>
<property name="location"/>
<map name="customPrices" table="custprice">
<key column="user"/>
<map-key-many-to-many column="product" class="Product"/>
<element column="price" type="double"/>
</map>
</class>
<class name="Product" table="product">
<id name="id" column="id">
<generator class="native"/>
</id>
<property name="name"/>
<property name="listprice"/>
</class>
</hibernate-mapping>
我尝试将lazy="false"
添加到类和各个属性中。没有区别。
我的配置文件:
<hibernate-configuration>
<session-factory>
<property name="connection.url">jdbc:mysql://192.168.0.203/hibtest</property>
<property name="connection.username">hibtest</property>
<property name="connection.password">hibb345</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property>
<property name="current_session_context_class">thread</property>
<property name="hibernate.show_sql">true</property>
<mapping resource="combined.hbm.xml" />
</session-factory>
</hibernate-configuration>
即使以下代码也会导致N + 1查询。虽然我只获取ID字段,但根据文档不应该导致加载对象。
for (Iterator i = q.iterate(); i.hasNext();) {
Object line = i.next();
User u = (User)((Map)line).get("obj");
System.out.println(u.getId());
}
答案 0 :(得分:8)
问题在于.iterate()
。根据{{3}}:
根据需要初始化结果时返回的实体。第一个SQL查询仅返回标识符。
当我们期望生成的对象已经缓存时,这是一个特殊的函数。访问时它们将被(懒惰)加载。
因此,对于一般用途,要获取查询结果的迭代器,您应该使用.list().iterate()
。
感谢您Hibernate API docs寻求帮助。
答案 1 :(得分:0)
在本质上,问题的原因是尝试将结果转换逻辑合并到查询中。
我认为最好是创建一个简单的HQL查询,然后在自定义ResultTransformer
中应用您的特定结果转换逻辑,如下所示:
Query q = mySession.createQuery("FROM User")
.setResultTransformer(new ResultTransformer() {
public List transformList(List l) { return l; }
public Object transformTuple(Object[] tuple, String[] aliases) {
Map<String, Object> r = new HashMap<String, Object>();
User u = (User) tuple[0];
r.put("obj", u);
r.put("id", u.getId());
r.put("text", u.getName());
return r;
}
});
答案 2 :(得分:0)
看起来它无法在单个查询中使用单独的列检索obj。
由于您对User使用与其他列相同的值,因此@axtavt中的示例似乎是您的最佳解决方案。