使用SQLQuery在Hibernate中使用sql语句_第1页
使用SQLQuery在Hibernate中使用sql语句_第2页
使用SQLQuery在Hibernate中使用sql语句_第3页
使用SQLQuery在Hibernate中使用sql语句_第4页
使用SQLQuery在Hibernate中使用sql语句_第5页
已阅读5页,还剩3页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、session.createSQLQuery.转载对原生SQL查询执行的控制是通过SQLQuery接口进行的,通过执行Session.createSQLQuery()获取这个接口。下面来描述如何使用这个API进行查询。1.标量查询(Scalar queries)最基本的SQL查询就是获得一个标量(数值)的列表。sess.createSQLQuery("SELECT * FROM CATS").list();sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").list();它们都将返回一个

2、Object数组(Object)组成的List,数组每个元素都是CATS表的一个字段值。Hibernate会使用ResultSetMetadata来判定返回的标量值的实际顺序和类型。如果要避免过多的使用ResultSetMetadata,或者只是为了更加明确的指名返回值,可以使用addScalar()。sess.createSQLQuery("SELECT * FROM CATS").addScalar("ID", Hibernate.LONG).addScalar("NAME", Hibernate.STRING).addScala

3、r("BIRTHDATE", Hibernate.DATE)这个查询指定了:· SQL查询字符串· 要返回的字段和类型它仍然会返回Object数组,但是此时不再使用ResultSetMetdata,而是明确的将ID,NAME和BIRTHDATE按照Long,String和Short类型从resultset中取出。同时,也指明了就算query是使用*来查询的,可能获得超过列出的这三个字段,也仅仅会返回这三个字段。对全部或者部分的标量值不设置类型信息也是可以的。sess.createSQLQuery("SELECT * FROM CATS"

4、;) .addScalar("ID", Hibernate.LONG) .addScalar("NAME") .addScalar("BIRTHDATE")基本上这和前面一个查询相同,只是此时使用ResultSetMetaData来决定NAME和BIRTHDATE的类型,而ID的类型是明确指出的。关于从ResultSetMetaData返回的java.sql.Types是如何映射到Hibernate类型,是由方言(Dialect)控制的。假若某个指定的类型没有被映射,或者不是你所预期的类型,你可以通过Dialet的registerHi

5、bernateType调用自行定义。2.实体查询(Entity queries)上面的查询都是返回标量值的,也就是从resultset中返回的“裸”数据。下面展示如何通过addEntity()让原生查询返回实体对象。sess.createSQLQuery("SELECT * FROM CATS").addEntity(Cat.class); sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").addEntity(Cat.class);这个查询指定:· SQL查询字符串

6、· 要返回的实体假设Cat被映射为拥有ID,NAME和BIRTHDATE三个字段的类,以上的两个查询都返回一个List,每个元素都是一个Cat实体。假若实体在映射时有一个many-to-one的关联指向另外一个实体,在查询时必须也返回那个实体,否则会导致发生一个"column not found"的数据库错误。这些附加的字段可以使用*标注来自动返回,但我们希望还是明确指明,看下面这个具有指向Dog的many-to-one的例子:sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, DOG_ID FROM CAT

7、S").addEntity(Cat.class);这样cat.getDog()就能正常运作。 下面的暂时没需求16.1.3. 处理关联和集合类(Handling associations and collections)通过提前抓取将Dog连接获得,而避免初始化proxy带来的额外开销也是可能的。这是通过addJoin()方法进行的,这个方法可以让你将关联或集合连接进来。sess.createSQLQuery("SELECT c.ID, NAME, BIRTHDATE, DOG_ID, D_ID, D_NAME FROM CATS c, DOGS d WHERE

8、c.DOG_ID = d.D_ID").addEntity("cat", Cat.class).addJoin("cat.dog");上面这个例子中,返回的Cat对象,其dog属性被完全初始化了,不再需要数据库的额外操作。注意,我们加了一个别名("cat"),以便指明join的目标属性路径。通过同样的提前连接也可以作用于集合类,例如,假若Cat有一个指向Dog的一对多关联。sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, D_ID, D_NAME, CAT_ID FR

9、OM CATS c, DOGS d WHERE c.ID = d.CAT_ID") .addEntity("cat", Cat.class) .addJoin("cat.dogs");到此为止,我们碰到了天花板:若不对SQL查询进行增强,这些已经是在Hibernate中使用原生SQL查询所能做到的最大可能了。下面的问题即将出现:返回多个同样类型的实体怎么办?或者默认的别名/字段不够又怎么办?16.1.4. 返回多个实体(Returning multiple entities)到目前为止,结果集字段名被假定为和映射文件中指定的的字段名是一致的。假

10、若SQL查询连接了多个表,同一个字段名可能在多个表中出现多次,这就会造成问题。下面的查询中需要使用字段别名注射(这个例子本身会失败):sess.createSQLQuery("SELECT c.*, m.* FROM CATS c, CATS m WHERE c.MOTHER_ID = c.ID") .addEntity("cat", Cat.class) .addEntity("mother", Cat.class)这个查询的本意是希望每行返回两个Cat实例,一个是cat,另一个是它的妈妈。但 是因为它们的字段名被映射为相同的,而且

11、在某些数据库中,返回的字段别名是“c.ID”,"c.NAME"这样的形式,而它们和在映射文件中的名字 ("ID"和"NAME")不匹配,这就会造成失败。下面的形式可以解决字段名重复:sess.createSQLQuery("SELECT cat.*, mother.* FROM CATS c, CATS m WHERE c.MOTHER_ID = c.ID") .addEntity("cat", Cat.class) .addEntity("mother", Cat.clas

12、s)这个查询指明:· SQL查询语句,其中包含占位附来让Hibernate注射字段别名· 查询返回的实体上面使用的cat.*和mother.*标记是作为“所有属性”的简写形式 出现的。当然你也可以明确地罗列出字段名,但在这个例子里面我们让Hibernate来为每个属性注射SQL字段别名。字段别名的占位符是属性名加上表别 名的前缀。在下面的例子中,我们从另外一个表(cat_log)中通过映射元数据中的指定获取Cat和它的妈妈。注意,要是我们愿意,我们甚至可以在 where子句中使用属性别名。String sql = "SELECT ID as c.id, NAME

13、as , " + "BIRTHDATE as c.birthDate, MOTHER_ID as c.mother, mother.* " + "FROM CAT_LOG c, CAT_LOG m WHERE c.mother = c.ID" List loggedCats = sess.createSQLQuery(sql) .addEntity("cat", Cat.class) .addEntity("mother", Cat.class).list(). 别名和属性引用

14、(Alias and property references)大多数情况下,都需要上面的属性注射,但在使用更加复杂的映射,比如复合属性、通过标识符构造继承树,以及集合类等等情况下,也有一些特别的别名,来允许Hibernate注射合适的别名。下表列出了使用别名注射参数的不同可能性。注意:下面结果中的别名只是示例,实用时每个别名需要唯一并且不同的名字。表 16.1. 别名注射(alias injection names)描述语法示例简单属性pertynameA_NAME as 复合属性pertynam

15、eCURRENCY as item.amount.currency, VALUE as item.amount.value实体辨别器(Discriminator of an entity)aliasname.classDISC as item.class实体的所有属性aliasname.*item.*集合键(collection key)aliasname.keyORGID as coll.key集合idaliasname.idEMPID as coll.id集合元素aliasname.elementXID as coll.element 集合元素的属性aliasname.eleme

16、pertynameNAME as  集合元素的所有属性aliasname.element.*coll.element.* 集合的所有属性aliasname.*coll.* 16.1.5. 返回非受管实体(Returning non-managed entities)可以对原生sql 查询使用ResultTransformer。这会返回不受Hibernate管理的实体。sess.createSQLQuery("SELECT NAME, BIRTHDATE FROM CATS") .setResultT

17、ransformer(Transformers.aliasToBean(CatDTO.class)这个查询指定:· SQL查询字符串· 结果转换器(result transformer)上面的查询将会返回CatDTO的列表,它将被实例化并且将NAME和BIRTHDAY的值注射入对应的属性或者字段。16.1.6. 处理继承(Handling inheritance)原生SQL查询假若其查询结果实体是继承树中的一部分,它必须包含基类和所有子类的所有属性。16.1.7. 参数(Parameters)原生查询支持位置参数和命名参数:Query query = sess.create

18、SQLQuery("SELECT * FROM CATS WHERE NAME like ?").addEntity(Cat.class); List pusList = query.setString(0, "Pus%").list(); query = sess.createSQLQuery("SELECT * FROM CATS WHERE NAME like :name").addEntity(Cat.class); List pusList = query.setString("name", "

19、Pus%").list();16.2. 命名SQL查询可以在映射文档中定义查询的名字,然后就可以象调用一个命名的HQL查询一样直接调用命名SQL查询.在这种情况下,我们addEntity()方法.<sql-query > <return alias="person" class="eg.Person"/> SELECT person.NAME AS , person.AGE AS person.age, person.SEX AS person.sex FROM PERSON person WHER

20、E person.NAME LIKE :namePattern </sql-query>List people = sess.getNamedQuery("persons") .setString("namePattern", namePattern) .setMaxResults(50) .list();<return-join>和 <load-collection> 元素是用来连接关联以及将查询定义为预先初始化各个集合的。<sql-query > <return alias=&

21、quot;person" class="eg.Person"/> <return-join alias="address" property="person.mailingAddress"/> SELECT person.NAME AS , person.AGE AS person.age, person.SEX AS person.sex, adddress.STREET AS address.street, adddress.CITY AS address.city, adddre

22、ss.STATE AS address.state, adddress.ZIP AS address.zip FROM PERSON person JOIN ADDRESS adddress ON person.ID = address.PERSON_ID AND address.TYPE='MAILING' WHERE person.NAME LIKE :namePattern </sql-query>一个命名查询可能会返回一个标量值.你必须使用<return-scalar>元素来指定字段的别名和 Hibernate类型<sql-query &g

23、t; <return-scalar column="name" type="string"/> <return-scalar column="age" type="long"/> SELECT p.NAME AS name, p.AGE AS age, FROM PERSON p WHERE p.NAME LIKE 'Hiber%' </sql-query>你可以把结果集映射的信息放在外部的<resultset>元素中,这样就可以在多个命名查询间,或者

24、通过setResultSetMapping()API来访问。(此处原文即存疑。原文为:You can externalize the resultset mapping informations in a <resultset>element to either reuse them accross several named queries or through the setResultSetMapping() API.)<resultset > <return alias="person" class=&qu

25、ot;eg.Person"/> <return-join alias="address" property="person.mailingAddress"/> </resultset> <sql-query name="personsWith" resultset-ref="personAddress"> SELECT person.NAME AS , person.AGE AS person.age, person.SEX AS perso

26、n.sex, adddress.STREET AS address.street, adddress.CITY AS address.city, adddress.STATE AS address.state, adddress.ZIP AS address.zip FROM PERSON person JOIN ADDRESS adddress ON person.ID = address.PERSON_ID AND address.TYPE='MAILING' WHERE person.NAME LIKE :namePattern </sql-query>另外,

27、你可以在java代码中直接使用hbm文件中的结果集定义信息。List cats = sess.createSQLQuery( "select cat.*, kitten.* from cats cat, cats kitten where kitten.mother = cat.id" ) .setResultSetMapping("catAndKitten") .list();16.2.1. 使用return-property来明确地指定字段/别名使用<return-property>你可以明确的告诉Hibernate使用哪些字段别名,这取

28、代了使用-语法 来让Hibernate注入它自己的别名.<sql-query > <return alias="person" class="eg.Person"> <return-property name="name" column="myName"/> <return-property name="age" column="myAge"/> <return-property name="sex"

29、column="mySex"/> </return> SELECT person.NAME AS myName, person.AGE AS myAge, person.SEX AS mySex, FROM PERSON person WHERE person.NAME LIKE :name </sql-query><return-property>也可用于多个字段,它解决了使用-语法不能细粒度控制多个字段的限制 <sql-query > <return alias="emp" class=&q

30、uot;Employment"> <return-property name="salary"> <return-column name="VALUE"/> <return-column name="CURRENCY"/> </return-property> <return-property name="endDate" column="myEndDate"/> </return> SELECT EMPLO

31、YEE AS emp.employee, EMPLOYER AS emp.employer, STARTDATE AS emp.startDate, ENDDATE AS emp.endDate, REGIONCODE as emp.regionCode, EID AS emp.id, VALUE, CURRENCY FROM EMPLOYMENT WHERE EMPLOYER = :id AND ENDDATE IS NULL ORDER BY STARTDATE ASC </sql-query>注意在这个例子中,我们使用了<return-property>结合的注入

32、语法. 允许用户来选择如何引用字段以及属性.如果你映射一个识别器(discriminator),你必须使用<return-discriminator> 来指定识别器字段16.2.2. 使用存储过程来查询Hibernate 3引入了对存储过程查询(stored procedure)和函数(function)的支持.以下的说明中,这二者一般都适用。 存储过程/函数必须返回一个结果集,作为Hibernate能够使用的第一个外部参数. 下面是一个Oracle9和更高版本的存储过程例子.CREATE OR REPLACE FUNCTION selectAllEmployments

33、RETURN SYS_REFCURSOR AS st_cursor SYS_REFCURSOR; BEGIN OPEN st_cursor FOR SELECT EMPLOYEE, EMPLOYER, STARTDATE, ENDDATE, REGIONCODE, EID, VALUE, CURRENCY FROM EMPLOYMENT; RETURN st_cursor; END;在Hibernate里要要使用这个查询,你需要通过命名查询来映射它.<sql-query callable="true"> <return alias="emp&qu

34、ot; class="Employment"> <return-property name="employee" column="EMPLOYEE"/> <return-property name="employer" column="EMPLOYER"/> <return-property name="startDate" column="STARTDATE"/> <return-property name

35、="endDate" column="ENDDATE"/> <return-property name="regionCode" column="REGIONCODE"/> <return-property name="id" column="EID"/> <return-property name="salary"> <return-column name="VALUE"/> &l

36、t;return-column name="CURRENCY"/> </return-property> </return> ? = call selectAllEmployments() </sql-query>注意存储过程当前仅仅返回标量和实体.现在不支持<return-join>和<load-collection>. 使用存储过程的规则和限制为了在Hibernate中使用存储过程,你必须遵循一些规则.不遵循这些规则的存储过程将不可用.如果你仍然想要使用他们, 你必须通过session.c

37、onnection()来执行他们.这些规则针对于不同的数据库.因为数据库 提供商有各种不同的存储过程语法和语义.对存储过程进行的查询无法使用setFirstResult()/setMaxResults()进行分页。建议采用的调用方式是标准SQL92:  ? = call functionName(<parameters>)  或者  ? = call procedureName(<parameters>.原生调用语法不被支持。对于Oracle有如下规则:· 函数必须返回一个结果集。存储过程的第一个参数必须是OUT,它返回一个结果集

38、。这是通过Oracle 9或10的SYS_REFCURSOR类型来完成的。在Oracle中你需要定义一个REF CURSOR类型,参见Oracle的手册。对于Sybase或者MS SQL server有如下规则:· 存储过程必须返回一个结果集。.注意这些servers可能返回多个结果集以及更新的数目.Hibernate将取出第一条结果集作为它的返回值, 其他将被丢弃。· 如果你能够在存储过程里设定SET NOCOUNT ON,这可能会效率更高,但这不是必需的。16.3. 定制SQL用来create,update和deleteHibernate3能够使用定制的SQL语句来执行

39、create,update和delete操作。在Hibernate中,持久化的类和集合已经 包含了一套配置期产生的语句(insertsql, deletesql, updatesql等等),这些映射标记 <sql-insert>, <sql-delete>, and <sql-update>重载了 这些语句。<class > <id name="id"> <generator class="increment"/> </id> <pro

40、perty name="name" not-null="true"/> <sql-insert>INSERT INTO PERSON (NAME, ID) VALUES ( UPPER(?), ? )</sql-insert> <sql-update>UPDATE PERSON SET NAME=UPPER(?) WHERE ID=?</sql-update> <sql-delete>DELETE FROM PERSON WHERE ID=?</sql-delete> <

41、/class>这些SQL直接在你的数据库里执行,所以你可以自由的使用你喜欢的任意语法。但如果你使用数据库特定的语法, 这当然会降低你映射的可移植性。如果设定callable,则能够支持存储过程了。<class > <id name="id"> <generator class="increment"/> </id> <property name="name" not-null="true"/> <sql-insert callable=&quo

42、t;true">call createPerson (?, ?)</sql-insert> <sql-delete callable="true">? = call deletePerson (?)</sql-delete> <sql-update callable="true">? = call updatePerson (?, ?)</sql-update> </class>参数的位置顺序是非常重要的,他们必须和Hibernate所期待的顺序相同。你能够通过设定日志调试级别为org.hiberante.persister.entity, 来查看Hibernate所期待的顺序。在这个级别下, Hibernate将会打印出create,update和delete实体的静态SQL。(如果想看到预计的顺序。记得不要将定制SQL包含在映射文件 里, 因为他们会重载Hibernate生成的静态SQL。)在大多数情况下(最好这么做),存储过程需要返回插入/更新/删除的行数,因为Hibernate对语句的成功执行有些运行时的检查。 Hibernate常会把进行CUD操作的语句的第一个参数注册为一

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论