利用SQLQuery 在Hibernate中利用sql语句

 

2.2. 命名SQL查询

能够在酷炫文书档案中定义查询的名字,然后就能够象调用一个命名的HQL查询同1平素调用命名SQL查询.在那种景况下,大家addEntity()方法.

<sql-query > 
  <return alias="person" class="eg.Person"/> 
  SELECT person.NAME AS {person.name}, person.AGE AS {person.age}, person.SEX AS {person.sex} FROM PERSON person WHERE 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="person" class="eg.Person"/> 
  <return-join alias="address" property="person.mailingAddress"/> 
  SELECT person.NAME AS {person.name}, person.AGE AS {person.age}, person.SEX AS {person.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>

 

一个命名查询恐怕会回来1个标量值.你必须运用<return-scalar>要从来钦赐字段的别称和
Hibernate类型

<sql-query > 
  <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>要素中,那样就足以在多少个命名查询间,恐怕通过setResultSetMapping()API来访问。(此处原版的书文即存疑。原版的书文为:You
can externalize the resultset mapping informations in
<resultset>element to either reuse them accross several named
queries or through the setResultSetMapping() API.)

<resultset > 
  <return alias="person" class="eg.Person"/> 
  <return-join alias="address" property="person.mailingAddress"/> 
</resultset> 
<sql-query name="personsWith" resultset-ref="personAddress"> 
  SELECT person.NAME AS {person.name}, person.AGE AS {person.age}, person.SEX AS {person.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>

 

别的,你能够在java代码中央直机关接行使hbm文件中的结果集定义消息。

List cats = sess.createSQLQuery( "select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id" ) .setResultSetMapping("catAndKitten") .list();

 

二.1.三. 回到非受管实体(Returning non-managed entities)

能够对原生sql
查询利用ResultTransformer。那会回到不受Hibernate管理的实业。

sess.createSQLQuery("SELECT NAME, BIRTHDATE FROM CATS") .setResultTransformer(Transformers.aliasToBean(CatDTO.class))

以此查询钦赐:

  • SQL查询字符串

  • 结果转变器(result transformer)

地点的询问将会再次来到CatDTO的列表,它将被实例化并且将NAME和BIRTHDAY的值注射入对应的性质可能字段。

二.二.二.一. 运用存款和储蓄进程的条条框框和范围

为了在Hibernate中动用存款和储蓄过程,你不可能不服从一些规则.不依据那几个规则的贮存进度将不可用.假若你还是想要使用他们,
你不可能不经过session.connection()来推行他们.那几个规则针对于分化的数目库.因为数据库
提供商有种种不一样的积存进程语法和语义.

对存款和储蓄进度进展的询问不恐怕选用setFirstResult()/setMaxResults()开展分页。

提议使用的调用形式是正规SQL玖贰: { ? = call functionName(<parameters>) } 或者 { ? = call procedureName(<parameters>}.原生调用语法不被协理。

对此Oracle有如下规则:

  • 函数必须回到一个结出集。存款和储蓄进程的第3个参数必须是OUT,它回到1个结出集。那是通过Oracle
    九或拾的SYS_REFCURSOR类型来形成的。在Oracle中您要求定义1个REF CURSOR类型,参见Oracle的手册。

对此Sybase大概MS SQL server有如下规则:

  • 积存进程必须回到八个结果集。.注意那几个servers恐怕回到多少个结果集以及立异的数目.Hibernate将收取第3条结果集作为它的再次来到值,
    其余将被放任。

  • 假诺您可见在蕴藏进程里设定SET NOCOUNT ON,这恐怕会功效越来越高,但那不是必需的。

1.标量查询(Scalar queries)

最中央的SQL查询就是赚取四个标量(数值)的列表。

sess.createSQLQuery("SELECT * FROM CATS").list();
sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").list();

它们都将回到二个Object数组(Object[])组成的List,数组每种元素都以CATS表的三个字段值。Hibernate会使用ResultSetMetadata来判别重临的标量值的实际顺序和花色。

假定要防止过多的选拔ResultSetMetadata,或然只是为了特别明朗的内定重回值,能够利用addScalar()

sess.createSQLQuery("SELECT * FROM CATS").addScalar("ID", Hibernate.LONG).addScalar("NAME", Hibernate.STRING).addScalar("BIRTHDATE", Hibernate.DATE);

那么些查询钦点了:

  • SQL查询字符串

  • 要回来的字段和项目

它依然会回去Object数组,不过此时不再选拔ResultSetMetdata,而是显著的将ID,NAME和BIRTHDATE依照Long,String和Short类型从resultset中抽出。同时,也指明了固然query是选择*来查询的,恐怕获得超过列出的那八个字段,也唯有会再次回到那多少个字段。

对整个要么局部的标量值不设置类型音讯也是能够的。

sess.createSQLQuery("SELECT * FROM CATS") .addScalar("ID", Hibernate.LONG) .addScalar("NAME") .addScalar("BIRTHDATE");

基本上那和日前二个查询同一,只是此时使用ResultSetMetaData来控制NAME和BIRTHDATE的品种,而ID的品种是分明建议的。

有关从ResultSetMetaData重回的java.sql.Types是怎么映射到Hibernate类型,是由方言(Dialect)调整的。假使有些钦命的类型未有被映射,或然不是您所预期的门类,你能够经过Dialet的registerHibernateType调用自行定义。

2.1.5. 参数(Parameters)

原生查询扶助地方参数和命名参数:

Query query = sess.createSQLQuery("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", "Pus%").list();

二.1.四. 处理承接(Handling inheritance)

原生SQL查询要是其询问结果实体是继续树中的1某个,它必须带有基类和兼具子类的保有属性。

二.壹.2. 外号和性质引用(阿里as and property references)

绝大许多场地下,都须求地方的质量注射,但在应用越来越复杂的映照,比如复合属性、通过标志符构造承接树,以及集合类等等情形下,也有一部分尤其的别称,来允许Hibernate注射合适的小名。

下表列出了接纳别名注射参数的不等只怕性。注意:下边结果中的外号只是示例,实用时种种小名须要唯一起时分裂的名字。

表 16.壹. 小名注射(alias injection names)

描述 语法 示例
简单属性 {[aliasname].[propertyname] A_NAME as {item.name}
复合属性 {[aliasname].[componentname].[propertyname]} CURRENCY as {item.amount.currency}, VALUE as {item.amount.value}
实体辨别器(Discriminator of an entity) {[aliasname].class} DISC as {item.class}
实体的所有属性 {[aliasname].*} {item.*}
集合键(collection key) {[aliasname].key} ORGID as {coll.key}
集合id {[aliasname].id} EMPID as {coll.id}
集合元素 {[aliasname].element} XID as {coll.element}
集合元素的属性 {[aliasname].element.[propertyname]} NAME as {coll.element.name}
集合元素的所有属性 {[aliasname].element.*} {coll.element.*}
集合的所有属性 {[aliasname].*} {coll.*}

二.一. 拍卖涉及和集合类(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 c.DOG_ID = d.D_ID").addEntity("cat", Cat.class).addJoin("cat.dog");

上面这几个事例中,再次回到的Cat对象,其dog属性被统统开始化了,不再供给数据库的附加操作。注意,大家加了一个别名(“cat”),以便指明join的目标属性路径。通过一样的提前连接也能够功用于集合类,例如,纵然Cat有一个针对Dog的1对多涉及。

sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, D_ID, D_NAME, CAT_ID FROM CATS c, DOGS d WHERE c.ID = d.CAT_ID") .addEntity("cat", Cat.class) .addJoin("cat.dogs");

到此甘休,大家相见了天花板:若不对SQL查询举行抓牢,这么些曾经是在Hibernate中选用原生SQL查询所能做到的最大只怕了。

上边包车型地铁主题素材就要出现:再次来到多少个同样类型的实业如何做?可能暗中同意的外号/字段不够又如何做?

2.3. 定制SQL用来create,update和delete

Hibernate叁能够运用定制的SQL语句来推行create,update和delete操作。在Hibernate中,持久化的类和集聚已经
包罗了壹套配置期产生的言语(insertsql, deletesql,
updatesql等等),那几个映射标志 <sql-insert><sql-delete>,
and <sql-update>重载了 那一个讲话。

<class>
    <id name="id">
         <generator class="increment"/>
    </id>
     <property 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> 
</class>

 

那个SQL直接在你的数据Curry施行,所以您能够随意的运用你欢快的随机语法。但借使您利用数据库特定的语法,
那本来会下跌您映射的可移植性。

倘诺设定callable,则能够协助存款和储蓄进度了。

<class> 
  <id name="id"> 
    <generator class="increment"/> 
  </id> 
  <property name="name" not-null="true"/> 
  <sql-insert callable="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。(假设想看到推测的1壹。记得不要将定制SQL包括在炫丽文件里,
因为她俩会重载Hibernate生成的静态SQL。)

在多数动静下(最佳这么做),存款和储蓄过程须求回到插入/更新/删除的行数,因为Hibernate对话语的中标实践多少运行时的自笔者批评。
Hibernate常会把开始展览CUD操作的言辞的率先个参数注册为五个数值型输出参数。

CREATE OR REPLACE FUNCTION updatePerson (uid IN NUMBER, uname IN VARCHAR2) RETURN NUMBER IS BEGIN update PERSON set NAME = uname, where ID = uid; 
return SQL%ROWCOUNT; 
END updatePerson;

 

二.一.一. 赶回七个实体(Returning multiple entities)

到最近甘休,结果集字段名被假定为和照耀文件中钦赐的的字段名是同一的。假设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实例,1个是cat,另一个是它的母亲。不过因为它们的字段名被映射为一样的,而且在壹些数据库中,再次回到的字段外号是“c.ID”,”c.NAME”那样的格局,而它们和在炫人眼目文件中的名字(”ID”和”NAME”)不匹配,这就会导致倒闭。

下边的款式得以解决字段名重复:

sess.createSQLQuery("SELECT {cat.*}, {mother.*} FROM CATS c, CATS m WHERE c.MOTHER_ID = m.ID") .addEntity("cat", Cat.class) .addEntity("mother", Cat.class);

那个查询指明:

  • SQL查询语句,个中富含占位附来让Hibernate注射字段别称

  • 询问重临的实业

地点运用的{cat.*}和{mother.*}标志是作为“全部属性”的简写方式出现的。当然你也足以分明地罗列出字段名,但在那一个例子里面大家让Hibernate来为各样属性注射SQL字段别名。字段外号的占位符是属性名加上表外号的前缀。在底下的例子中,大家从其余二个表(cat_log)中经过映射元数据中的钦点获取Cat和它的老母。注意,假设大家甘愿,我们居然足以在where子句中利用属性小名。

String sql = "SELECT ID as {c.id}, NAME as {c.name}, " + "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();

对原生SQL查询实践的决定是透过SQLQuery接口实行的,通过施行Session.createSQLQuery()赢得这些接口。上面来叙述怎么着运用这几个API实行查询。

二.2.二. 施用存款和储蓄进度来询问

Hibernate 3引进了对存款和储蓄进度查询(stored
procedure)和函数(function)的帮助.以下的求证中,那两者1般都适用。
存款和储蓄进度/函数必须重回一个结实集,作为Hibernate能够利用的第一个外表参数.
上面是一个Oracle玖和越来越高版本的蕴藏进程例子.

CREATE OR REPLACE FUNCTION selectAllEmployments 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" class="Employment"> 
    <return-property name="employee" column="EMPLOYEE"/> 
    <return-property name="employer" column="EMPLOYER"/> 
    <return-property name="startDate" column="STARTDATE"/> 
    <return-property name="endDate" column="ENDDATE"/> 
    <return-property name="regionCode" column="REGIONCODE"/> 
    <return-property name="id" column="EID"/> 
    <return-property name="salary"> 
    <return-column name="VALUE"/> 
    <return-column name="CURRENCY"/> </return-property> 
  </return> { ? = call selectAllEmployments() } 
</sql-query>

 

瞩目存款和储蓄进度当前单纯再次来到标量和实业.现在不协助<return-join><load-collection>

二.实体查询(Entity queries)

地点的询问都以回去标量值的,也正是从resultset中回到的“裸”数据。下边彰显怎么样通过addEntity()让原生查询再次回到实体对象。

sess.createSQLQuery("SELECT * FROM CATS").addEntity(Cat.class); 
sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").addEntity(Cat.class);

其一查询钦赐:

  • SQL查询字符串

  • 要回去的实业

只要Cat被映射为富有ID,NAME和BIRTHDATE八个字段的类,以上的四个查询都回到二个List,每一个成分都是贰个Cat实体。

借使实体在炫人眼目时有三个many-to-one的关联指向其余3个实体,在查询时必须也回到那1个实体,不然会变成发生二个”column
not
found”的数据库错误。那一个附加的字段能够应用*标明来机关回到,但大家期待可能不言而喻指明,看下边那些装有针对性Dogmany-to-one的例子:

sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, DOG_ID FROM CATS").addEntity(Cat.class);

这么cat.getDog()就能不奇怪运作。

 


 

 

 

二.四. 定制装载SQL

你大概供给评释你自身的SQL(或HQL)来装载实体

<sql-query> 
  <return alias="pers" class="Person" lock-mode="upgrade"/> 
  SELECT NAME AS {pers.name}, ID AS {pers.id} FROM PERSON WHERE ID=? FOR UPDATE 
</sql-query>

 

那只是1个前边议论过的命名查询评释,你能够在类映射里引用这么些命名查询。

<class> 
  <id name="id"> 
    <generator class="increment"/> 
  </id> 
  <property name="name" not-null="true"/> 
  <loader query-ref="person"/> 
</class>

那也得以用于存款和储蓄进程

你甚至足以定二个用来集合装载的查询:

<set inverse="true"> 
  <key/> 
  <one-to-many class="Employment"/> 
  <loader query-ref="employments"/> 
</set>
<sql-query> 
  <load-collection alias="emp" role="Person.employments"/> 
  SELECT {emp.*} FROM EMPLOYMENT emp WHERE EMPLOYER = :id ORDER BY STARTDATE ASC, EMPLOYEE ASC 
</sql-query>

 

您仍然还足以定义二个实体装载器,它通过连接抓取装载三个汇集:

<sql-query> 
  <return alias="pers" class="Person"/> 
  <return-join alias="emp" property="pers.employments"/> 
  SELECT NAME AS {pers.*}, {emp.*} FROM PERSON pers LEFT OUTER JOIN EMPLOYMENT emp ON pers.ID = emp.PERSON_ID WHERE ID=? 
</sql-query>

转自:http://www.cnblogs.com/ejllen/p/3704599.html

二.二.一. 使用return-property来威名昭著地钦定字段/小名

使用<return-property>你能够显明的报告Hibernate使用什么字段别称,那代表了选择{}-语法
来让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" 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="Employment">
   <return-property name="salary">
     <return-column name="VALUE"/>
     <return-column name="CURRENCY"/>
   </return-property>
   <return-property name="endDate" column="myEndDate"/>
 </return>
 SELECT EMPLOYEE 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>结合{}的流入语法.
允许用户来挑选什么引用字段以及属性.

假若您映射一个识别器(discriminator),你不可能不采取<return-discriminator> 来钦赐识别器字段

相关文章