[极品难]关于hibernate如何把原生sql查出的结果转化为对象

例如我们有一个照片的PO

Java code
//照片po
class Photo
{
   int id;
   string title;
   double avgScore;//平均分,这个字段在数据库中是没有映射的,也就是 非持久化属性
}

//投票po ,每张照片对应多个vote记录
class Vote
{
   int id;
   int photoId;
   int score;
}



用sql = "select {p.*,avg(v.score) as p.avgScore} from photo p left join vote v on p.id = v.photoId ";
单纯的sql结果很满意,包含照片的信息和每张照片的平均分数。

代码如下:
Query query = session.createSQLQuery(sql.toString()).addEntity(Photo.class);

运行后,没有错误,但是在SQL语句中的avg(v.score) as p.avgScore} 这一部分,没有被像我们预期的那样set进photo的avgScore属性中。


问题:
我们如果遇到要用原生sql进行查询,并要将结果set进一个po中,其中set进po中的属性,不完全是被可持久化的,例如本例
中的avgScore属性。

期待大家来解答这个疑惑~谢谢! thanks a lot !

PS: 请别和我说完全可以用hql等方式,这只是个简单的示例,目前是想研究原生sql对象映射问题。

问题补充:
首先谢谢yangtao309您的回答!~

我仔细看了那篇文章,addScalar这个的意思似乎只是把查出来的非属性结果进行类型绑定,我现在的困惑是如果把这个值自动绑定进po中~~

就像上面的例子,select出一个po,然后这个po中要有那个avgScore的属性值,目前我试过即使用addScalar明确avgScore的类型,还是不会自动set进po中。。

是不是我哪弄错了,还是什么原因,希望大家再帮我看看
问题补充:
谢谢您 walsh 的回答,我觉得您说的很有道理 ,我现在用的MYSQL5,按您的提示,运行后,控制台打出下样异常,繁请帮忙看下,谢谢!



打印出的SQL:
sql:  select {p.id,p.user_id,p.url,p.state,avg(v.score) as p.avgScore} from photos p  where p.user_id = :userId and p.state in ( 0, 1 )  group by p.id  order by  p.id desc





报了个这个错:
44187 [http-8080-1] WARN org.hibernate.util.JDBCExceptionReporter - SQL Error: 1064, SQLState: 42000
44187 [http-8080-1] ERROR org.hibernate.util.JDBCExceptionReporter - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'from photos p  where p.user_id = 13 and p.state in ( 0, 1 )  group by p.id  orde' at line 1
2009-9-3 12:04:39 org.apache.catalina.core.StandardWrapperValve invoke
严重: Servlet.service() for servlet default threw exception
com.mysql.jdbc.exceptions.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'from photos p  where p.user_id = 13 and p.state in ( 0, 1 )  group by p.id  orde' at line 1
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:936)

问题补充:
为什么要对所有字段字组??这原因和自动set进po应该没直接关系吧?

问题补充:
改成group by p.id, p.user_id,p.url,p.state仍然是之前的错误。

如果不加{}那么就报在数据库找不到p.avgScore这列,因为p.avgScore是一个虚似的临时变量,非持久化属性。

谢谢,再帮忙想想~~~
问题补充:
谢谢,WALSH再次的回答。

我提问题时只是简单写的示例,省略了几个字段,
sql = "select p.id,avg(v.score) from photo p , vote v where p.id = v.photoId  group by p.id";  

这么写是可以,但不会被自动绑定进PO,我来问就是想知道在不调用SET方法的情况下能否自动把非字段属性绑定进PO。

如果是单调set方法,我是知道的~~有没有自动的方式,谢谢walsh不遗余力的帮我解决这个问题。谢谢!

您看看有没有自动的方式绑定进PO的。。

问题补充:
您好walsh,我也知道hibernate会找set方法,但有可能还会只限制在*.hbm.xml文件中声明,或者只被@Cloumn注解的属性字段。。

因为我返回avg(v.score) as p.avgScore,其实在p这个po中是有setAvgScore()这个方法的,可是终始不会被调用 。。。

我甚至做过这个测试,把avgScore()设成@Cloumn(insertable=false,updateable=false),还是不会自动set进po中。。


对这个问题看来基本明确了。。可能就是不行,只能返回object[]来一个个的set了吧?

10个回答

[quote]avg(v.score) as p.avgScore[/quote]

前面我不是给你说过了吗,你这样写,只是为平均分avg(v.score)起了一个名字是p.avgScore,这个名只是字符串,和你所谓的引用变量没有任何关系,明白吗

你这个地方主要是这样写了,如果你换为

[quote]avg(v.score) as 平均分[/quote]

这样也是对的,as后面只是一个别名,和属性还有引用变量p没有任何关系。

给你个帖子看看
[url]http://jihongbin12329.iteye.com/blog/88678[/url]

[code="java"]addScalar[/code]
很重要

[code="java"]Query qu =session.createSQLQuery("select NID, {b.*} from user_account , user_archive {b} where NID = {b}.NUSER_ID and NID = "+userId).addEntity("b", UserArchive.class).addScalar("NID",new LongType());

[/code]

[quote]avg(v.score) as p.avgScore} [/quote]

你这样做只是将avg(v.score)的结果所在的列命名为 p.avgScore,在这里 p.avgScore只是一个字符串,和赋值没有任何关系。

把你的SQL语句改为:
[code="SQL"]sql = "select {p.id,p.title,avg(v.score) as p.avgScore} from photo p left join vote v on p.id = v.photoId "; [/code]

这样查询出来的结果每一行就对应着photo的一个记录,然后你遍历该结果,每读一行,就把该行封装为photo对象就行了,在这个时候,才是调用set方法来完成封装的。

[quote]sql = "select {p.*,avg(v.score) as p.avgScore} from photo p left join vote v on p.id = v.photoId "; [/quote]

貌似你这里 不能用p.* p.* 就已经包含了你要知道的avg(v.score)对应po中的属性
你试试楼上 说的那么用看

[code="java"] group by p.id [/code]
分组需要 group by p.id, p.title的
所有查询字段 都需要分组

[quote]
select {p.id,p.user_id,p.url,p.state,avg(v.score) as p.avgScore} from photos p where p.user_id = :userId and p.state in ( 0, 1 ) group by p.id order by p.id desc
[/quote]

这个sql语句就有错误
group by 用法
先不管那么多 你写成
[code="java"]
select {p.id,p.user_id,p.url,p.state,avg(v.score) as p.avgScore} from photos p where p.user_id = :userId and p.state in ( 0, 1 ) group by p.id, p.user_id,p.url,p.state order by p.id desc
[/code]
先试试 再看看

貌似 不需要 "{}" 。。。。

[quote]sql: select {p.id,p.user_id,p.url,p.state,avg(v.score) as p.avgScore} from photos p where p.user_id = :userId and p.state in ( 0, 1 ) group by p.id order by p.id desc [/quote]

出现异常,说明你的SQL语句写的有问题。

你的SQL语句中,p.user_id 从那来的,p.state 又是从那来的,是你的表结构里的字段吗,既然是,那为什么和你的实体类Phote中的属性不一致的,貌似你类里面没有这些属性呀。

[size=large]楼主,你用下面的SQL,直接复制过去。我已经通过测试了,是正确的,获取的是每个photo的平均分.[/size]

[code="SQL"]sql = "select p.id,avg(v.score) from photo p , vote v where p.id = v.photoId group by p.id"; [/code]

楼主,按照上面的SQL语句查到的是每一个photo的id对应的平均分,这个不就是你想要的吗,然后遍历没条语句,调用Photo类中相应的set方法不就可以了吗

我来问就是想知道在不调用SET方法的情况下能否自动把非字段属性绑定进PO

我可以明确的回答你这个问题,如果非字段属性是做不到的。

Hibernate之所以能够做到将字段值持久化到数据表中相应字段上,或者是从数据表中的相应字段上读取值,然后返回一个对象,该对象就持有了该属性的值,能够做到上面这些,就在于它的映射文件,以及java中的反射机制。

通过字段名自动调用该字段的set方法。

可你现在时从数据库中读取的数据就没有改字段,你咋让它用反射调用相应的set方法吧。

除非是,你的PO和数据库中表的字段一一对应的。

上面我给你说的方法,应该来说,是可以的。

Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问