Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
lect17-hibernate-orm / more / hibernate_reference.pdf
Скачиваний:
90
Добавлен:
18.03.2015
Размер:
2.2 Mб
Скачать

Chapter 18. Native SQL

The recommended call form is standard SQL92: { ? = call functionName(<parameters>) }

or { ? = call procedureName(<parameters>}. Native call syntax is not supported.

For Oracle the following rules apply:

A function must return a result set. The first parameter of a procedure must be an OUT that returns a result set. This is done by using a SYS_REFCURSOR type in Oracle 9 or 10. In Oracle you need to define a REF CURSOR type. See Oracle literature for further information.

For Sybase or MS SQL server the following rules apply:

The procedure must return a result set. Note that since these servers can return multiple result sets and update counts, Hibernate will iterate the results and take the first result that is a result set as its return value. Everything else will be discarded.

If you can enable SET NOCOUNT ON in your procedure it will probably be more efficient, but this is not a requirement.

18.3. Custom SQL for create, update and delete

Hibernate3 can use custom SQL for create, update, and delete operations. The SQL can be overridden at the statement level or inidividual column level. This section describes statement overrides. For columns, see Section 5.6, “Column transformers: read and write expressions”.

Example 18.11, “Custom CRUD via annotations” shows how to define custom SQL operatons using annotations.

Example 18.11. Custom CRUD via annotations

@Entity @Table(name="CHAOS")

@SQLInsert( sql="INSERT INTO CHAOS(size, name, nickname, id) VALUES(?,upper(?),?,?)") @SQLUpdate( sql="UPDATE CHAOS SET size = ?, name = upper(?), nickname = ? WHERE id = ?") @SQLDelete( sql="DELETE CHAOS WHERE id = ?")

@SQLDeleteAll( sql="DELETE CHAOS") @Loader(namedQuery = "chaos")

@NamedNativeQuery(name="chaos", query="select id, size, name, lower( nickname ) as nickname from CHAOS where id= ?", resultClass = Chaos.class)

public class Chaos { @Id

private Long id; private Long size; private String name;

private String nickname;

@SQLInsert, @SQLUpdate, @SQLDelete, @SQLDeleteAll respectively override the INSERT, UPDATE, DELETE, and DELETE all statement. The same can be achieved using Hibernate mapping files and the <sql-insert>, <sql-update> and <sql-delete> nodes. This can be seen in Example 18.12, “Custom CRUD XML”.

310

Custom SQL for create, update and delete

Example 18.12. Custom CRUD XML

<class name="Person"> <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>

If you expect to call a store procedure, be sure to set the callable attribute to true. In annotations as well as in xml.

To check that the execution happens correctly, Hibernate allows you to define one of those three strategies:

none: no check is performed: the store procedure is expected to fail upon issues

count: use of rowcount to check that the update is successful

param: like COUNT but using an output parameter rather that the standard mechanism

To define the result check style, use the check parameter which is again available in annoations as well as in xml.

You can use the exact same set of annotations respectively xml nodes to override the collection related statements -see Example 18.13, “Overriding SQL statements for collections using annotations”.

Example 18.13. Overriding SQL statements for collections using

annotations

@OneToMany @JoinColumn(name="chaos_fk")

@SQLInsert( sql="UPDATE CASIMIR_PARTICULE SET chaos_fk = ? where id = ?") @SQLDelete( sql="UPDATE CASIMIR_PARTICULE SET chaos_fk = null where id = ?") private Set<CasimirParticle> particles = new HashSet<CasimirParticle>();

Tip

The parameter order is important and is defined by the order Hibernate handles properties. You can see the expected order by enabling debug logging for the org.hibernate.persister.entity level. With this level enabled Hibernate will print out the static SQL that is used to create, update, delete etc. entities. (To

311

Chapter 18. Native SQL

see the expected sequence, remember to not include your custom SQL through annotations or mapping files as that will override the Hibernate generated static sql)

Overriding SQL statements for secondary tables is also possible using

@org.hibernate.annotations.Table and either (or all) attributes sqlInsert, sqlUpdate,

sqlDelete:

Example 18.14. Overriding SQL statements for secondary tables

@Entity

@SecondaryTables({

@SecondaryTable(name = "`Cat nbr1`"), @SecondaryTable(name = "Cat2"})

@org.hibernate.annotations.Tables( {

@Table(appliesTo = "Cat", comment = "My cat table" ),

@Table(appliesTo = "Cat2", foreignKey = @ForeignKey(name="FK_CAT2_CAT"), fetch = FetchMode.SELECT, sqlInsert=@SQLInsert(sql="insert into Cat2(storyPart2, id) values(upper(?), ?)") )

} )

public class Cat implements Serializable {

The previous example also shows that you can give a comment to a given table (primary or secondary): This comment will be used for DDL generation.

Tip

The SQL is directly executed in your database, so you can use any dialect you like. This will, however, reduce the portability of your mapping if you use database specific SQL.

Last but not least, stored procedures are in most cases required to return the number of rows inserted, updated and deleted. Hibernate always registers the first statement parameter as a numeric output parameter for the CUD operations:

Example 18.15. Stored procedures and their return value

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;

312

Custom SQL for loading

END updatePerson;

18.4. Custom SQL for loading

You can also declare your own SQL (or HQL) queries for entity loading. As with inserts, updates, and deletes, this can be done at the individual column level as described in Section 5.6, “Column transformers: read and write expressions” or at the statement level. Here is an example of a statement level override:

<sql-query name="person">

<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>

This is just a named query declaration, as discussed earlier. You can reference this named query in a class mapping:

<class name="Person"> <id name="id">

<generator class="increment"/>

</id>

<property name="name" not-null="true"/> <loader query-ref="person"/>

</class>

This even works with stored procedures.

You can even define a query for collection loading:

<set name="employments" inverse="true">

<key/>

<one-to-many class="Employment"/> <loader query-ref="employments"/>

</set>

<sql-query name="employments">

<load-collection alias="emp" role="Person.employments"/> SELECT {emp.*}

FROM EMPLOYMENT emp

WHERE EMPLOYER = :id

ORDER BY STARTDATE ASC, EMPLOYEE ASC </sql-query>

313

Chapter 18. Native SQL

You can also define an entity loader that loads a collection by join fetching:

<sql-query name="person">

<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>

The annotation equivalent <loader> is the @Loader annotation as seen in Example 18.11, “Custom CRUD via annotations”.

314

Соседние файлы в папке more