hibernate映射文件不支持union联合查询

        专门给用户培训的环境后台日志最近报出一个异常,

org.hibernate.exception.SQLGrammarException: could not execute query
	at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:67)
	at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
	at org.hibernate.loader.Loader.doList(Loader.java:2214)
	at com.cnpc.oms.dao.BaseHibernateDAO.pagedQuery(BaseHibernateDAO.java:280)
……
Caused by: java.sql.SQLException: ORA-00907: 缺失右括号

	at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:112)
	at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:331)
	at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:288)
	at oracle.jdbc.driver.T4C8Oall.receive(T4C8Oall.java:743)
	... 38 more

        取出hibernate后台日志打印的sql语句分析,出问题的这段sql语句为:

select *
  from (select this_.SUB_ID as ACID1_1373_0_,
               ......
               this_.OPER_DATE as OPER19_1373_0_,
               (select t.well_name
                  from BASE_WELL_INFO t
                 where t.well_id =
                       ((select t.well_id
                           from SUPER_TABLE_1 t
                          where t.ID = this_.TASK_ID
                            and rownum = 1 this_.union
                           select t.well_id
                                   from SUPER_TABLE_2 t
                                  where t.ID =
                                        this_.TASK_ID
                                    and rownum = 1 this_.union
                                   select t.well_id
                                           from SUPER_TABLE_3 t
                                          where t.ID =
                                                this_.TASK_ID
                                            and rownum = 1 this_.union
                                           select t.well_id
                                                   from SUPER_TABLE_4 t
                                                  where t.ID =
                                                        this_.TASK_ID
                                                    and rownum = 1
                         ))
                   and rownum = 1) as formula1982_0_,
               ......
          from SUB_TABLE this_)
 where rownum <= ?

        Hibernate映射文件中这段sql是这样记录的

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- 
	Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping>
	<class name="……" table="SUB_TABLE">
		<comment>…… </comment>
		<id name="subId" type="java.lang.String">
			<column name="SUB_ID" length="32" />
			<generator class="uuid.hex" />
		</id>
        ……
		<property name="wellName" type="java.lang.String">
			<formula>
				(select t.well_name
					  from base_well_info t
					 where t.well_id = ((select t.well_id
					                       from SUPER_TABLE_1 t
					                      where t. ID = TASK_ID
					                        and rownum = 1
					                     union
					                     select t.well_id
					                       from SUPER_TABLE_2 t
					                      where t. ID = TASK_ID
					                        and rownum = 1
					                     union
					                     select t.well_id
					                       from SUPER_TABLE_3 t
					                      where t. ID = TASK_ID
					                        and rownum = 1
					                     union
					                     select t.well_id
					                       from SUPER_TABLE_4 t
					                      where t.ID = TASK_ID
					                        and rownum = 1))
					   and rownum = 1
				)
			</formula>
		</property>
		……
	</class>
</hibernate-mapping>

        SUB_TABLE表中的外键TASK_ID字段的数据是来自表SUPER_TABLE_1SUPER_TABLE_2SUPER_TABLE_3SUPER_TABLE_4中的主键ID,表SUPER_TABLE_1SUPER_TABLE_2SUPER_TABLE_3SUPER_TABLE_4中的外键WELL_ID数据来自表BASE_WELL_INFO的主键,主要目的就是通过关联取到表BASE_WELL_INFO中的WELL_NAME井名。

        通过日志可以看出hibernate直接把union关键字解释成了字段this_.union,这样在执行sql查询语句的时候就报出了上面的异常。也不知道当时开发这个模块的人员到底有么有开发完成,并测试通过。

        在网上找了好半天, 也没有找到一个好的处理方法。自己整理了一下处理方式。

        自己建了3张表,模拟项目中的业务表。

        教师和学生都需要考试,考试的结果存放在同一张成绩表中。

--创建教师表
create table TEACHER
(
  ID   VARCHAR2(32) not null,--主键
  NAME VARCHAR2(32) --教师姓名
)
-- Create/Recreate primary, unique and foreign key constraints 
alter table TEACHER
  add constraint TEACHER_PRI_ID primary key (ID)
--创建学生表
create table STUDENT
(
  ID   VARCHAR2(32) not null,--主键
  NAME VARCHAR2(32) --学生姓名
)
-- Create/Recreate primary, unique and foreign key constraints 
alter table STUDENT
  add constraint STUDENT_PRI_ID primary key (ID)
--创建考试成绩表
create table SCORE
(
  ID          VARCHAR2(32) not null,--主键
  PERSON_TYPE VARCHAR2(32), --考试人类别
  SCORE       NUMBER(4,1), --考试分数
  PERSON_ID   VARCHAR2(32) --考试人ID,记录学生表和教师表中的ID
)
-- Create/Recreate primary, unique and foreign key constraints 
alter table SCORE
  add constraint SCORE_PRI_ID primary key (ID)

        jsp页面上要显示成绩表SCORE中的记录,假如显示信息包括考试者姓名和相应的考试成绩,查询成绩数据项好说,直接从成绩表中的SCORE字段取出,但是考试者姓名是存放在不同的表中。成绩表SCORE中的PERSON_ID字段记录的人员ID来自不同的表。

        Hibernate映射配置文件中,如果不支持union联合查询,使用union显然是行不通的,可以通过下面的方式尝试。

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
	<class name="com.test.pojo.Score" table="SCORE">
		<comment>老师、学生的成绩</comment>
		<id name="id" type="java.lang.String">
			<column name="ID" length="32" />
			<generator class="uuid.hex" />
		</id>
		<property name="personType" type="java.lang.String">
			<column name="PERSON_TYPE" length="32">
				<comment>考试人员类别</comment>
			</column>
		</property>
		<property name="personId" type="java.lang.String">
			<column name="PERSON_ID" length="32">
				<comment>考试人员ID</comment>
			</column>
		</property>
		<property name="score" type="java.lang.Double">
			<column name="SCORE" precision="4" scale="1">
				<comment>考试成绩</comment>
			</column>
		</property>
		<!-- 根据成绩表SCORE中的人员主键PERSON_ID,直接分别到TEACHER、STUDENT表中查询相应人员的名字,
				并且存放在不同的映射字段中 -->
		<!-- 老师姓名 -->
		<property name="teaPersonName" type="java.lang.String">
			<formula>
				( SELECT d.NAME
					  FROM TEACHER d
					 WHERE d.ID = PERSON_ID
					   AND ROWNUM = 1
					)
			</formula>
		</property>
		<!-- 学生姓名 -->
		<property name="stuPersonName" type="java.lang.String">
			<formula>
				( SELECT d.NAME
					  FROM STUDENT d
					 WHERE d.ID = PERSON_ID
					   AND ROWNUM = 1
					)
			</formula>
		</property>
	</class>
</hibernate-mapping>

        SCORE对应的pojo中stuPersonNameteaPersonName两个字段的setter方法需要做一下调整。

import java.io.Serializable;
public class Score implements Serializable{

	private String id;
	private String personType;
	private Double score;
	private String personId;
	private String personName;//存放考试者姓名
	
	private String teaPersonName;//存放教师姓名
	private String stuPersonName;//存放学生姓名
	
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getPersonType() {
		return personType;
	}
	public void setPersonType(String personType) {
		this.personType = personType;
	}
	public Double getScore() {
		return score;
	}
	public void setScore(Double score) {
		this.score = score;
	}
	public String getPersonId() {
		return personId;
	}
	public void setPersonId(String personId) {
		this.personId = personId;
	}
	public String getPersonName() {
		return personName;
	}
	public void setPersonName(String personName) {
		this.personName = personName;
	}
	public String getTeaPersonName() {
		return teaPersonName;
	}
	public void setTeaPersonName(String teaPersonName) {
		if(null != teaPersonName){
			//根据外键PERSON_ID在教师表中查找到对应的姓名,如果查到结果,则直接赋值给personName
			this.personName = teaPersonName;
		}
	}
	public String getStuPersonName() {
		return stuPersonName;
	}
	public void setStuPersonName(String stuPersonName) {
		if(null != stuPersonName){
			//根据外键PERSON_ID在学生表中查找到对应的姓名,如果查到结果,则直接赋值给personName
			this.personName = stuPersonName;
		}
	}
}

        这样在页面直接取出Score.personName的值即可。

        上面记录的是一种处理方式。实际上通过观察发现业务表中还有一个字段存放着和外键相关的信息,就像上面的成绩表SCORE中的PERSON_TYPE字段。如果PERSON_TYPE=教师,就表明这一条数据就是教师的考试成绩,可以根据外键PERSON_ID直接到教师表TEACHER中查询姓名。

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
	<class name="com.test.pojo.Score" table="SCORE">
		<comment>老师、学生的成绩</comment>
		<id name="id" type="java.lang.String">
			<column name="ID" length="32" />
			<generator class="uuid.hex" />
		</id>
		<property name="personType" type="java.lang.String">
			<column name="PERSON_TYPE" length="32">
				<comment>考试人员类别</comment>
			</column>
		</property>
		<property name="personId" type="java.lang.String">
			<column name="PERSON_ID" length="32">
				<comment>考试人员ID</comment>
			</column>
		</property>
		<property name="score" type="java.lang.Double">
			<column name="SCORE" precision="4" scale="1">
				<comment>考试成绩</comment>
			</column>
		</property>
		<property name="personName" type="java.lang.String">
			<formula>
				( SELECT (CASE
					         WHEN t.PERSON_TYPE = '教师' THEN
					          (SELECT d.NAME FROM TEACHER d WHERE d.ID = PERSON_ID)
					         WHEN t.PERSON_TYPE = '学生' THEN
					          (SELECT d.NAME FROM STUDENT d WHERE d.ID = PERSON_ID)
					       END) AS PERSONNAME
					  FROM SCORE t
					 WHERE t.PERSON_ID = PERSON_ID
					   AND ROWNUM = 1
					)
			</formula>
		</property>
	</class>
</hibernate-mapping>
import java.io.Serializable;
public class Score implements Serializable{

	private String id;
	private String personType;
	private Double score;
	private String personId;
	private String personName;//存放考试者姓名
	
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getPersonType() {
		return personType;
	}
	public void setPersonType(String personType) {
		this.personType = personType;
	}
	public Double getScore() {
		return score;
	}
	public void setScore(Double score) {
		this.score = score;
	}
	public String getPersonId() {
		return personId;
	}
	public void setPersonId(String personId) {
		this.personId = personId;
	}
	public String getPersonName() {
		return personName;
	}
	public void setPersonName(String personName) {
		this.personName = personName;
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值