lots of improvements to native sql query documentation

git-svn-id: https://svn.jboss.org/repos/hibernate/trunk/Hibernate3/doc@6910 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Gavin King 2005-05-25 14:16:21 +00:00
parent cf39b7cb22
commit dc22aee899
1 changed files with 123 additions and 75 deletions

View File

@ -22,8 +22,8 @@
</para> </para>
<programlisting><![CDATA[List cats = sess.createSQLQuery("select {cat.*} from cats cat") <programlisting><![CDATA[List cats = sess.createSQLQuery("select {cat.*} from cats cat")
.addEntity("cat", Cat.class); .addEntity("cat", Cat.class)
.setMaxResults(50); .setMaxResults(50)
.list();]]></programlisting> .list();]]></programlisting>
<para> <para>
@ -50,9 +50,16 @@
<para> <para>
The <literal>addJoin()</literal> method may be used to load associations to other entities The <literal>addJoin()</literal> method may be used to load associations to other entities
and collections. TODO: examples! and collections.
</para> </para>
<programlisting><![CDATA[List cats = sess.createSQLQuery(
"select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id"
)
.addEntity("cat", Cat.class)
.addJoin("kitten", "cat.kittens")
.list();]]></programlisting>
<para> <para>
A native SQL query might return a simple scalar value or a combination of scalars and A native SQL query might return a simple scalar value or a combination of scalars and
entities. entities.
@ -70,14 +77,16 @@
<para> <para>
The <literal>{cat.*}</literal> notation used above is a shorthand for "all properties". The <literal>{cat.*}</literal> notation used above is a shorthand for "all properties".
Alternatively, you may list the columns explicity, but even then you must let Hibernate Alternatively, you may list the columns explicity, but even this case we let Hibernate
inject the SQL column aliases for each property. The placeholder for a column alias is inject the SQL column aliases for each property. The placeholder for a column alias is
just the property name qualified by the table alias. In the following example, we retrieve just the property name qualified by the table alias. In the following example, we retrieve
<literal>Cat</literal>s from a different table (<literal>cat_log</literal>) to the one <literal>Cat</literal>s from a different table (<literal>cat_log</literal>) to the one
declared in the mapping metadata. Notice that we may even use the property aliases in the declared in the mapping metadata. Notice that we may even use the property aliases in the
where clause if we like. where clause if we like.
</para>
The <literal>{}</literal>-syntax is not required for named queries. See more in <xref linkend="querysql-namedqueries"/> <para>
The <literal>{}</literal>-syntax is <emphasis>not</emphasis> required for named queries.
See <xref linkend="querysql-namedqueries"/>
</para> </para>
<programlisting><![CDATA[String sql = "select cat.originalId as {cat.id}, " + <programlisting><![CDATA[String sql = "select cat.originalId as {cat.id}, " +
@ -101,23 +110,47 @@ List loggedCats = sess.createSQLQuery(sql)
<title>Named SQL queries</title> <title>Named SQL queries</title>
<para> <para>
Named SQL queries may be defined in the mapping document and called in exactly the same way Named SQL queries may be defined in the mapping document and called in exactly the
as a named HQL query. In this case, we do <emphasis>not</emphasis> need to call same way as a named HQL query. In this case, we do <emphasis>not</emphasis> need
<literal>addEntity()</literal>. to call <literal>addEntity()</literal>.
</para> </para>
<programlisting><![CDATA[<sql-query name="mySqlQuery"> <programlisting><![CDATA[<sql-query name="persons">
<return alias="person" class="eg.Person"/> <return alias="person" class="eg.Person"/>
SELECT person.NAME AS {person.name}, SELECT person.NAME AS {person.name},
person.AGE AS {person.age}, person.AGE AS {person.age},
person.SEX AS {person.sex} person.SEX AS {person.sex}
FROM PERSON person WHERE person.NAME LIKE 'Hiber%' FROM PERSON person
WHERE person.NAME LIKE :namePattern
</sql-query>]]></programlisting> </sql-query>]]></programlisting>
<programlisting><![CDATA[List people = sess.getNamedQuery("mySqlQuery") <programlisting><![CDATA[List people = sess.getNamedQuery("persons")
.setString("namePattern", namePattern)
.setMaxResults(50) .setMaxResults(50)
.list();]]></programlisting> .list();]]></programlisting>
<para>
The <literal>&lt;return-join&gt;</literal> and <literal>&lt;load-collection&gt;</literal>
elements are used to join associations and define queries which initialize collections,
respectively.
</para>
<programlisting><![CDATA[<sql-query name="personsWith">
<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>]]></programlisting>
<para> <para>
A named SQL query may return a scalar value. You must specfy the column alias A named SQL query may return a scalar value. You must specfy the column alias
and Hibernate type using the <literal>&lt;return-scalar&gt;</literal> element: and Hibernate type using the <literal>&lt;return-scalar&gt;</literal> element:
@ -131,18 +164,13 @@ List loggedCats = sess.createSQLQuery(sql)
FROM PERSON p WHERE p.NAME LIKE 'Hiber%' FROM PERSON p WHERE p.NAME LIKE 'Hiber%'
</sql-query>]]></programlisting> </sql-query>]]></programlisting>
<para>
The <literal>&lt;return-join&gt;</literal> and <literal>&lt;load-collection&gt;</literal>
elements are used to join associations and define queries which initialize collections,
respectively. TODO!
</para>
<sect2 id="propertyresults"> <sect2 id="propertyresults">
<title>Using return-property to explicitly specify column/alias names</title> <title>Using return-property to explicitly specify column/alias names</title>
<para> <para>
With <literal>&lt;return-property&gt;</literal> you can explicitly tell Hibernate what columns With <literal>&lt;return-property&gt;</literal> you can explicitly tell Hibernate what column
to use as opposed to use <literal>{}</literal>-syntax to let Hibernate inject its own aliases. aliases to use, instead of using the <literal>{}</literal>-syntax to let Hibernate inject its
own aliases.
</para> </para>
<programlisting><![CDATA[<sql-query name="mySqlQuery"> <programlisting><![CDATA[<sql-query name="mySqlQuery">
@ -158,8 +186,11 @@ List loggedCats = sess.createSQLQuery(sql)
</sql-query> </sql-query>
]]></programlisting> ]]></programlisting>
<literal>&lt;return-property&gt;</literal> also works with multiple columns. This solves a limitation with <para>
the <literal>{}</literal>-syntax which can not allow fine grained control of multi-column properties. <literal>&lt;return-property&gt;</literal> also works with multiple columns. This solves a
limitation with the <literal>{}</literal>-syntax which can not allow fine grained control
of multi-column properties.
</para>
<programlisting><![CDATA[<sql-query name="organizationCurrentEmployments"> <programlisting><![CDATA[<sql-query name="organizationCurrentEmployments">
<return alias="emp" class="Employment"> <return alias="emp" class="Employment">
@ -184,8 +215,8 @@ List loggedCats = sess.createSQLQuery(sql)
</para> </para>
<para> <para>
If your mapping has a discriminator you must use &lt;return-discriminator&gt; to specify the If your mapping has a discriminator you must use <literal>&lt;return-discriminator&gt;</literal>
discriminator column. to specify the discriminator column.
</para> </para>
</sect2> </sect2>
@ -193,11 +224,10 @@ List loggedCats = sess.createSQLQuery(sql)
<title>Using stored procedures for querying</title> <title>Using stored procedures for querying</title>
<para> <para>
Hibernate 3 introduces support for queries via stored procedures. Hibernate 3 introduces support for queries via stored procedures. The stored procedures must
return a resultset as the first out-parameter to be able to work with Hibernate. An example
The stored procedures must return a resultset as the first out-parameter to be able to work with Hibernate. of such a stored procedure in Oracle 9 and higher is as follows:
</para>
An example of such a stored procedure in Oracle 9 and higher is as follows:
<programlisting><![CDATA[CREATE OR REPLACE FUNCTION selectAllEmployments <programlisting><![CDATA[CREATE OR REPLACE FUNCTION selectAllEmployments
RETURN SYS_REFCURSOR RETURN SYS_REFCURSOR
@ -212,7 +242,9 @@ BEGIN
RETURN st_cursor; RETURN st_cursor;
END;]]></programlisting> END;]]></programlisting>
<para>
To use this query in Hibernate you need to map it via a named query. To use this query in Hibernate you need to map it via a named query.
</para>
<programlisting><![CDATA[<sql-query name="selectAllEmployees_SP" callable="true"> <programlisting><![CDATA[<sql-query name="selectAllEmployees_SP" callable="true">
<return alias="emp" class="Employment"> <return alias="emp" class="Employment">
@ -229,7 +261,6 @@ BEGIN
</return> </return>
{ ? = call selectAllEmployments() } { ? = call selectAllEmployments() }
</sql-query>]]></programlisting> </sql-query>]]></programlisting>
</para>
<para> <para>
Notice stored procedures currently only return scalars and entities. Notice stored procedures currently only return scalars and entities.
@ -259,14 +290,16 @@ BEGIN
<itemizedlist spacing="compact"> <itemizedlist spacing="compact">
<listitem> <listitem>
<para> <para>
The procedure must return a result set. This is done by returning a SYS_REFCURSOR in Oracle 9 The procedure must return a result set. This is done by returning a
or 10. In Oracle you need to define a <literal>REF CURSOR</literal> type. <literal>SYS_REFCURSOR</literal> in Oracle 9 or 10. In Oracle you
need to define a <literal>REF CURSOR</literal> type.
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
Recommended form is <literal>{ ? = call procName(&lt;parameters&gt;) }</literal> or Recommended form is <literal>{ ? = call procName(&lt;parameters&gt;) }</literal>
<literal>{ ? = call procName }</literal> (This is more an Oracle rule than a Hibernate rule.) or <literal>{ ? = call procName }</literal> (this is more an Oracle rule than a
Hibernate rule).
</para> </para>
</listitem> </listitem>
</itemizedlist> </itemizedlist>
@ -342,9 +375,11 @@ BEGIN
</para> </para>
<para> <para>
You can see the expected order by enabling debug logging for the <literal>org.hiberante.persister.entity</literal> You can see the expected order by enabling debug logging for the
level. With this level enabled Hibernate will print out the static SQL that is used to create, update, delete etc. entities. <literal>org.hibernate.persister.entity</literal> level. With this level enabled
To see the expected sequence, remember to not include your custom SQL in the mapping files as that will override the Hibernate generated static sql. Hibernate will print out the static SQL that is used to create, update, delete etc.
entities. (To see the expected sequence, remember to not include your custom SQL in
the mapping files as that will override the Hibernate generated static sql.)
</para> </para>
<para> <para>
@ -379,8 +414,11 @@ END updatePerson;]]></programlisting>
</para> </para>
<programlisting><![CDATA[<sql-query name="person"> <programlisting><![CDATA[<sql-query name="person">
<return alias="p" class="Person" lock-mode="upgrade"/> <return alias="pers" class="Person" lock-mode="upgrade"/>
SELECT NAME AS {p.name}, ID AS {p.id} FROM PERSON WHERE ID=? FOR UPDATE SELECT NAME AS {pers.name}, ID AS {pers.id}
FROM PERSON
WHERE ID=?
FOR UPDATE
</sql-query>]]></programlisting> </sql-query>]]></programlisting>
<para> <para>
@ -397,30 +435,40 @@ END updatePerson;]]></programlisting>
</class>]]></programlisting> </class>]]></programlisting>
<para> <para>
And this also works with stored procedures. This even works with stored procedures.
</para> </para>
<para> <para>
TODO: Document the following example for collection loader. You may even define a query for collection loading:
</para> </para>
<programlisting><![CDATA[<sql-query name="organizationEmployments"> <programlisting><![CDATA[<set name="employments" inverse="true">
<load-collection alias="empcol" role="Organization.employments"/> <key/>
SELECT {empcol.*} <one-to-many class="Employment"/>
FROM EMPLOYMENT empcol <loader query-ref="employments"/>
</set>]]></programlisting>
<programlisting><![CDATA[<sql-query name="employments">
<load-collection alias="emp" role="Person.employments"/>
SELECT {emp.*}
FROM EMPLOYMENT emp
WHERE EMPLOYER = :id WHERE EMPLOYER = :id
ORDER BY STARTDATE ASC, EMPLOYEE ASC ORDER BY STARTDATE ASC, EMPLOYEE ASC
</sql-query> </sql-query>]]></programlisting>
<sql-query name="organizationCurrentEmployments"> <para>
<return alias="emp" class="Employment"/> You could even define an entity loader that loads a collection by
<synchronize table="EMPLOYMENT"/> join fetching:
SELECT EMPLOYEE AS {emp.employee}, EMPLOYER AS {emp.employer}, </para>
STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate},
REGIONCODE as {emp.regionCode}, ID AS {emp.id} <programlisting><![CDATA[<sql-query name="person">
FROM EMPLOYMENT <return alias="pers" class="Person"/>
WHERE EMPLOYER = :id AND ENDDATE IS NULL <return-join alias="emp" property="pers.employments"/>
ORDER BY STARTDATE ASC SELECT NAME AS {pers.*}, {emp.*}
FROM PERSON pers
LEFT OUTER JOIN EMPLOYMENT emp
ON pers.ID = emp.PERSON_ID
WHERE ID=?
</sql-query>]]></programlisting> </sql-query>]]></programlisting>
</sect1> </sect1>