documented use of unqualified property names in HQL

fixed some of the problems in the SQL chapter


git-svn-id: https://svn.jboss.org/repos/hibernate/trunk/Hibernate3/doc@6215 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Gavin King 2005-03-25 05:18:45 +00:00
parent e1e8adccd4
commit abbf47ed61
2 changed files with 224 additions and 182 deletions

View File

@ -38,16 +38,20 @@
<programlisting><![CDATA[from eg.Cat]]></programlisting> <programlisting><![CDATA[from eg.Cat]]></programlisting>
<para> <para>
which simply returns all instances of the class <literal>eg.Cat</literal>. which simply returns all instances of the class <literal>eg.Cat</literal>.
We don't usually need to qualify the class name, since <literal>auto-import</literal>
is the default. So we almost always just write:
</para> </para>
<programlisting><![CDATA[from Cat]]></programlisting>
<para> <para>
Most of the time, you will need to assign an <emphasis>alias</emphasis>, since Most of the time, you will need to assign an <emphasis>alias</emphasis>, since
you will want to refer to the <literal>Cat</literal> in other parts of the you will want to refer to the <literal>Cat</literal> in other parts of the
query. query.
</para> </para>
<programlisting><![CDATA[from eg.Cat as cat]]></programlisting> <programlisting><![CDATA[from Cat as cat]]></programlisting>
<para> <para>
This query assigns the alias <literal>cat</literal> to <literal>Cat</literal> This query assigns the alias <literal>cat</literal> to <literal>Cat</literal>
@ -55,7 +59,7 @@
keyword is optional; we could also write: keyword is optional; we could also write:
</para> </para>
<programlisting><![CDATA[from eg.Cat cat]]></programlisting> <programlisting><![CDATA[from Cat cat]]></programlisting>
<para> <para>
Multiple classes may appear, resulting in a cartesian product or "cross" join. Multiple classes may appear, resulting in a cartesian product or "cross" join.
@ -80,13 +84,13 @@
collection of values, using a <literal>join</literal>. collection of values, using a <literal>join</literal>.
</para> </para>
<programlisting><![CDATA[from eg.Cat as cat <programlisting><![CDATA[from Cat as cat
inner join cat.mate as mate inner join cat.mate as mate
left outer join cat.kittens as kitten left outer join cat.kittens as kitten]]></programlisting>
from eg.Cat as cat left join cat.mate.kittens as kittens <programlisting><![CDATA[from Cat as cat left join cat.mate.kittens as kittens]]></programlisting>
from Formula form full join form.parameter param]]></programlisting> <programlisting><![CDATA[from Formula form full join form.parameter param]]></programlisting>
<para> <para>
The supported join types are borrowed from ANSI SQL The supported join types are borrowed from ANSI SQL
@ -120,7 +124,7 @@ from Formula form full join form.parameter param]]></programlisting>
<literal>right outer join</literal> constructs may be abbreviated. <literal>right outer join</literal> constructs may be abbreviated.
</para> </para>
<programlisting><![CDATA[from eg.Cat as cat <programlisting><![CDATA[from Cat as cat
join cat.mate as mate join cat.mate as mate
left join cat.kittens as kitten]]></programlisting> left join cat.kittens as kitten]]></programlisting>
@ -132,7 +136,7 @@ from Formula form full join form.parameter param]]></programlisting>
<xref linkend="performance-fetching"/> for more information. <xref linkend="performance-fetching"/> for more information.
</para> </para>
<programlisting><![CDATA[from eg.Cat as cat <programlisting><![CDATA[from Cat as cat
inner join fetch cat.mate inner join fetch cat.mate
left join fetch cat.kittens]]></programlisting> left join fetch cat.kittens]]></programlisting>
@ -162,7 +166,7 @@ from Formula form full join form.parameter param]]></programlisting>
</para> </para>
<programlisting><![CDATA[select mate <programlisting><![CDATA[select mate
from eg.Cat as cat from Cat as cat
inner join cat.mate as mate]]></programlisting> inner join cat.mate as mate]]></programlisting>
<para> <para>
@ -170,7 +174,7 @@ from eg.Cat as cat
Actually, you may express this query more compactly as: Actually, you may express this query more compactly as:
</para> </para>
<programlisting><![CDATA[select cat.mate from eg.Cat cat]]></programlisting> <programlisting><![CDATA[select cat.mate from Cat cat]]></programlisting>
<!-- NO LONGER SUPPORTED! <!-- NO LONGER SUPPORTED!
@ -179,13 +183,13 @@ from eg.Cat as cat
function. The following query returns all kittens of any cat. function. The following query returns all kittens of any cat.
</para> </para>
<programlisting><![CDATA[select elements(cat.kittens) from eg.Cat cat]]></programlisting> <programlisting><![CDATA[select elements(cat.kittens) from Cat cat]]></programlisting>
--> -->
<para> <para>
Queries may return properties of any value type including properties of component type: Queries may return properties of any value type including properties of component type:
</para> </para>
<programlisting><![CDATA[select cat.name from eg.DomesticCat cat <programlisting><![CDATA[select cat.name from DomesticCat cat
where cat.name like 'fri%' where cat.name like 'fri%'
select cust.name.firstName from Customer as cust]]></programlisting> select cust.name.firstName from Customer as cust]]></programlisting>
@ -196,7 +200,7 @@ select cust.name.firstName from Customer as cust]]></programlisting>
</para> </para>
<programlisting><![CDATA[select mother, offspr, mate.name <programlisting><![CDATA[select mother, offspr, mate.name
from eg.DomesticCat as mother from DomesticCat as mother
inner join mother.mate as mate inner join mother.mate as mate
left outer join mother.kittens as offspr]]></programlisting> left outer join mother.kittens as offspr]]></programlisting>
@ -205,7 +209,7 @@ from eg.DomesticCat as mother
</para> </para>
<programlisting><![CDATA[select new Family(mother, mate, offspr) <programlisting><![CDATA[select new Family(mother, mate, offspr)
from eg.DomesticCat as mother from DomesticCat as mother
join mother.mate as mate join mother.mate as mate
left join mother.kittens as offspr]]></programlisting> left join mother.kittens as offspr]]></programlisting>
@ -223,7 +227,7 @@ from eg.DomesticCat as mother
</para> </para>
<programlisting><![CDATA[select avg(cat.weight), sum(cat.weight), max(cat.weight), count(cat) <programlisting><![CDATA[select avg(cat.weight), sum(cat.weight), max(cat.weight), count(cat)
from eg.Cat cat]]></programlisting> from Cat cat]]></programlisting>
<!-- NO LONGER SUPPORTED <!-- NO LONGER SUPPORTED
<para> <para>
@ -232,7 +236,7 @@ from eg.Cat cat]]></programlisting>
</para> </para>
<programlisting><![CDATA[select cat, count( elements(cat.kittens) ) <programlisting><![CDATA[select cat, count( elements(cat.kittens) )
from eg.Cat cat group by cat]]></programlisting> from Cat cat group by cat]]></programlisting>
--> -->
<para> <para>
@ -262,9 +266,9 @@ from eg.Cat cat group by cat]]></programlisting>
the same semantics as in SQL. the same semantics as in SQL.
</para> </para>
<programlisting><![CDATA[select distinct cat.name from eg.Cat cat <programlisting><![CDATA[select distinct cat.name from Cat cat
select count(distinct cat.name), count(cat) from eg.Cat cat]]></programlisting> select count(distinct cat.name), count(cat) from Cat cat]]></programlisting>
</sect1> </sect1>
@ -275,7 +279,7 @@ select count(distinct cat.name), count(cat) from eg.Cat cat]]></programlisting>
A query like: A query like:
</para> </para>
<programlisting><![CDATA[from eg.Cat as cat]]></programlisting> <programlisting><![CDATA[from Cat as cat]]></programlisting>
<para> <para>
returns instances not only of <literal>Cat</literal>, but also of subclasses like returns instances not only of <literal>Cat</literal>, but also of subclasses like
@ -292,7 +296,7 @@ select count(distinct cat.name), count(cat) from eg.Cat cat]]></programlisting>
classes: classes:
</para> </para>
<programlisting><![CDATA[from eg.Named n, eg.Named m where n.name = m.name]]></programlisting> <programlisting><![CDATA[from Named n, Named m where n.name = m.name]]></programlisting>
<para> <para>
Note that these last two queries will require more than one SQL <literal>SELECT</literal>. This Note that these last two queries will require more than one SQL <literal>SELECT</literal>. This
@ -307,16 +311,23 @@ select count(distinct cat.name), count(cat) from eg.Cat cat]]></programlisting>
<para> <para>
The <literal>where</literal> clause allows you to narrow the list of instances returned. The <literal>where</literal> clause allows you to narrow the list of instances returned.
If no alias exists, you may refer to properties by name:
</para> </para>
<programlisting><![CDATA[from eg.Cat as cat where cat.name='Fritz']]></programlisting> <programlisting><![CDATA[from Cat where name='Fritz']]></programlisting>
<para>
If there is an alias, use a qualified property name:
</para>
<programlisting><![CDATA[from Cat as cat where cat.name='Fritz']]></programlisting>
<para> <para>
returns instances of <literal>Cat</literal> named 'Fritz'. returns instances of <literal>Cat</literal> named 'Fritz'.
</para> </para>
<programlisting><![CDATA[select foo <programlisting><![CDATA[select foo
from eg.Foo foo, eg.Bar bar from Foo foo, Bar bar
where foo.startDate = bar.date]]></programlisting> where foo.startDate = bar.date]]></programlisting>
<para> <para>
@ -328,14 +339,14 @@ where foo.startDate = bar.date]]></programlisting>
<literal>where</literal> clause extremely powerful. Consider: <literal>where</literal> clause extremely powerful. Consider:
</para> </para>
<programlisting><![CDATA[from eg.Cat cat where cat.mate.name is not null]]></programlisting> <programlisting><![CDATA[from Cat cat where cat.mate.name is not null]]></programlisting>
<para> <para>
This query translates to an SQL query with a table (inner) join. If you were to write This query translates to an SQL query with a table (inner) join. If you were to write
something like something like
</para> </para>
<programlisting><![CDATA[from eg.Foo foo <programlisting><![CDATA[from Foo foo
where foo.bar.baz.customer.address.city is not null]]></programlisting> where foo.bar.baz.customer.address.city is not null]]></programlisting>
<para> <para>
@ -347,10 +358,10 @@ where foo.bar.baz.customer.address.city is not null]]></programlisting>
instances: instances:
</para> </para>
<programlisting><![CDATA[from eg.Cat cat, eg.Cat rival where cat.mate = rival.mate <programlisting><![CDATA[from Cat cat, Cat rival where cat.mate = rival.mate]]></programlisting>
select cat, mate <programlisting><![CDATA[select cat, mate
from eg.Cat cat, eg.Cat mate from Cat cat, Cat mate
where cat.mate = mate]]></programlisting> where cat.mate = mate]]></programlisting>
<para> <para>
@ -358,9 +369,9 @@ where cat.mate = mate]]></programlisting>
unique identifier of an object. (You may also use its property name.) unique identifier of an object. (You may also use its property name.)
</para> </para>
<programlisting><![CDATA[from eg.Cat as cat where cat.id = 123 <programlisting><![CDATA[from Cat as cat where cat.id = 123
from eg.Cat as cat where cat.mate.id = 69]]></programlisting> from Cat as cat where cat.mate.id = 69]]></programlisting>
<para> <para>
The second query is efficient. No table join is required! The second query is efficient. No table join is required!
@ -374,9 +385,9 @@ from eg.Cat as cat where cat.mate.id = 69]]></programlisting>
<programlisting><![CDATA[from bank.Person person <programlisting><![CDATA[from bank.Person person
where person.id.country = 'AU' where person.id.country = 'AU'
and person.id.medicareNumber = 123456 and person.id.medicareNumber = 123456]]></programlisting>
from bank.Account account <programlisting><![CDATA[from bank.Account account
where account.owner.id.country = 'AU' where account.owner.id.country = 'AU'
and account.owner.id.medicareNumber = 123456]]></programlisting> and account.owner.id.medicareNumber = 123456]]></programlisting>
@ -390,7 +401,7 @@ where account.owner.id.country = 'AU'
where clause will be translated to its discriminator value. where clause will be translated to its discriminator value.
</para> </para>
<programlisting><![CDATA[from eg.Cat cat where cat.class = eg.DomesticCat]]></programlisting> <programlisting><![CDATA[from Cat cat where cat.class = DomesticCat]]></programlisting>
<para> <para>
You may also specify properties of components or composite user types (and of components You may also specify properties of components or composite user types (and of components
@ -408,8 +419,8 @@ store.owner.address // error!]]></programlisting>
is a property mapped with <literal>&lt;any&gt;</literal>). is a property mapped with <literal>&lt;any&gt;</literal>).
</para> </para>
<programlisting><![CDATA[from eg.AuditLog log, eg.Payment payment <programlisting><![CDATA[from AuditLog log, Payment payment
where log.item.class = 'eg.Payment' and log.item.id = payment.id]]></programlisting> where log.item.class = 'Payment' and log.item.id = payment.id]]></programlisting>
<para> <para>
Notice that <literal>log.item.class</literal> and <literal>payment.class</literal> Notice that <literal>log.item.class</literal> and <literal>payment.class</literal>
@ -513,17 +524,17 @@ where log.item.class = 'eg.Payment' and log.item.id = payment.id]]></programlist
<literal>in</literal> and <literal>between</literal> may be used as follows: <literal>in</literal> and <literal>between</literal> may be used as follows:
</para> </para>
<programlisting><![CDATA[from eg.DomesticCat cat where cat.name between 'A' and 'B' <programlisting><![CDATA[from DomesticCat cat where cat.name between 'A' and 'B']]></programlisting>
from eg.DomesticCat cat where cat.name in ( 'Foo', 'Bar', 'Baz' )]]></programlisting> <programlisting><![CDATA[from DomesticCat cat where cat.name in ( 'Foo', 'Bar', 'Baz' )]]></programlisting>
<para> <para>
and the negated forms may be written and the negated forms may be written
</para> </para>
<programlisting><![CDATA[from eg.DomesticCat cat where cat.name not between 'A' and 'B' <programlisting><![CDATA[from DomesticCat cat where cat.name not between 'A' and 'B']]></programlisting>
from eg.DomesticCat cat where cat.name not in ( 'Foo', 'Bar', 'Baz' )]]></programlisting> <programlisting><![CDATA[from DomesticCat cat where cat.name not in ( 'Foo', 'Bar', 'Baz' )]]></programlisting>
<para> <para>
Likewise, <literal>is null</literal> and <literal>is not null</literal> may be used to test Likewise, <literal>is null</literal> and <literal>is not null</literal> may be used to test
@ -542,16 +553,16 @@ from eg.DomesticCat cat where cat.name not in ( 'Foo', 'Bar', 'Baz' )]]></progra
literals <literal>1</literal> and <literal>0</literal> in the translated SQL from this HQL: literals <literal>1</literal> and <literal>0</literal> in the translated SQL from this HQL:
</para> </para>
<programlisting><![CDATA[from eg.Cat cat where cat.alive = true]]></programlisting> <programlisting><![CDATA[from Cat cat where cat.alive = true]]></programlisting>
<para> <para>
You may test the size of a collection with the special property <literal>size</literal>, or You may test the size of a collection with the special property <literal>size</literal>, or
the special <literal>size()</literal> function. the special <literal>size()</literal> function.
</para> </para>
<programlisting><![CDATA[from eg.Cat cat where cat.kittens.size > 0 <programlisting><![CDATA[from Cat cat where cat.kittens.size > 0]]></programlisting>
from eg.Cat cat where size(cat.kittens) > 0]]></programlisting> <programlisting><![CDATA[from Cat cat where size(cat.kittens) > 0]]></programlisting>
<para> <para>
For indexed collections, you may refer to the minimum and maximum indices using For indexed collections, you may refer to the minimum and maximum indices using
@ -561,11 +572,11 @@ from eg.Cat cat where size(cat.kittens) > 0]]></programlisting>
functions. functions.
</para> </para>
<programlisting><![CDATA[from Calendar cal where maxelement(cal.holidays) > current date <programlisting><![CDATA[from Calendar cal where maxelement(cal.holidays) > current date]]></programlisting>
from Order order where maxindex(order.items) > 100 <programlisting><![CDATA[from Order order where maxindex(order.items) > 100]]></programlisting>
from Order order where minelement(order.items) > 10000]]></programlisting> <programlisting><![CDATA[from Order order where minelement(order.items) > 10000]]></programlisting>
<para> <para>
The SQL functions <literal>any, some, all, exists, in</literal> are supported when passed the element The SQL functions <literal>any, some, all, exists, in</literal> are supported when passed the element
@ -573,17 +584,17 @@ from Order order where minelement(order.items) > 10000]]></programlisting>
or the result of a subquery (see below). or the result of a subquery (see below).
</para> </para>
<programlisting><![CDATA[select mother from eg.Cat as mother, eg.Cat as kit <programlisting><![CDATA[select mother from Cat as mother, Cat as kit
where kit in elements(foo.kittens) where kit in elements(foo.kittens)]]></programlisting>
select p from eg.NameList list, eg.Person p <programlisting><![CDATA[select p from NameList list, Person p
where p.name = some elements(list.names) where p.name = some elements(list.names)]]></programlisting>
from eg.Cat cat where exists elements(cat.kittens) <programlisting><![CDATA[from Cat cat where exists elements(cat.kittens)]]></programlisting>
from eg.Player p where 3 > all elements(p.scores) <programlisting><![CDATA[from Player p where 3 > all elements(p.scores)]]></programlisting>
from eg.Show show where 'fizard' in indices(show.acts)]]></programlisting> <programlisting><![CDATA[from Show show where 'fizard' in indices(show.acts)]]></programlisting>
<para> <para>
Note that these constructs - <literal>size</literal>, <literal>elements</literal>, Note that these constructs - <literal>size</literal>, <literal>elements</literal>,
@ -597,16 +608,16 @@ from eg.Show show where 'fizard' in indices(show.acts)]]></programlisting>
index (in a where clause only): index (in a where clause only):
</para> </para>
<programlisting><![CDATA[from Order order where order.items[0].id = 1234 <programlisting><![CDATA[from Order order where order.items[0].id = 1234]]></programlisting>
select person from Person person, Calendar calendar <programlisting><![CDATA[select person from Person person, Calendar calendar
where calendar.holidays['national day'] = person.birthDay where calendar.holidays['national day'] = person.birthDay
and person.nationality.calendar = calendar and person.nationality.calendar = calendar]]></programlisting>
select item from Item item, Order order <programlisting><![CDATA[select item from Item item, Order order
where order.items[ order.deliveredItemIndices[0] ] = item and order.id = 11 where order.items[ order.deliveredItemIndices[0] ] = item and order.id = 11]]></programlisting>
select item from Item item, Order order <programlisting><![CDATA[select item from Item item, Order order
where order.items[ maxindex(order.items) ] = item and order.id = 11]]></programlisting> where order.items[ maxindex(order.items) ] = item and order.id = 11]]></programlisting>
<para> <para>
@ -629,7 +640,7 @@ where index(item) < 5]]></programlisting>
Scalar SQL functions supported by the underlying database may be used Scalar SQL functions supported by the underlying database may be used
</para> </para>
<programlisting><![CDATA[from eg.DomesticCat cat where upper(cat.name) like 'FRI%']]></programlisting> <programlisting><![CDATA[from DomesticCat cat where upper(cat.name) like 'FRI%']]></programlisting>
<para> <para>
If you are not yet convinced by all this, think how much longer and less readable the If you are not yet convinced by all this, think how much longer and less readable the
@ -675,7 +686,7 @@ WHERE prod.name = 'widget'
The list returned by a query may be ordered by any property of a returned class or components: The list returned by a query may be ordered by any property of a returned class or components:
</para> </para>
<programlisting><![CDATA[from eg.DomesticCat cat <programlisting><![CDATA[from DomesticCat cat
order by cat.name asc, cat.weight desc, cat.birthdate]]></programlisting> order by cat.name asc, cat.weight desc, cat.birthdate]]></programlisting>
<para> <para>
@ -692,11 +703,11 @@ order by cat.name asc, cat.weight desc, cat.birthdate]]></programlisting>
</para> </para>
<programlisting><![CDATA[select cat.color, sum(cat.weight), count(cat) <programlisting><![CDATA[select cat.color, sum(cat.weight), count(cat)
from eg.Cat cat from Cat cat
group by cat.color group by cat.color]]></programlisting>
select foo.id, avg(name), max(name) <programlisting><![CDATA[select foo.id, avg(name), max(name)
from eg.Foo foo join foo.names name from Foo foo join foo.names name
group by foo.id]]></programlisting> group by foo.id]]></programlisting>
<para> <para>
@ -704,18 +715,18 @@ group by foo.id]]></programlisting>
</para> </para>
<programlisting><![CDATA[select cat.color, sum(cat.weight), count(cat) <programlisting><![CDATA[select cat.color, sum(cat.weight), count(cat)
from eg.Cat cat from Cat cat
group by cat.color group by cat.color
having cat.color in (eg.Color.TABBY, eg.Color.BLACK)]]></programlisting> having cat.color in (eg.Color.TABBY, eg.Color.BLACK)]]></programlisting>
<para> <para>
SQL functions and aggregate functions are allowed in the <literal>having</literal> SQL functions and aggregate functions are allowed in the <literal>having</literal>
and <literal>order by</literal> clauses, if supported by the underlying database (eg. and <literal>order by</literal> clauses, if supported by the underlying database
not in MySQL). (eg. not in MySQL).
</para> </para>
<programlisting><![CDATA[select cat <programlisting><![CDATA[select cat
from eg.Cat cat from Cat cat
join cat.kittens kitten join cat.kittens kitten
group by cat group by cat
having avg(kitten.weight) > 100 having avg(kitten.weight) > 100
@ -737,24 +748,24 @@ order by count(kitten) asc, sum(kitten.weight) desc]]></programlisting>
(subqueries that refer to an alias in the outer query) are allowed. (subqueries that refer to an alias in the outer query) are allowed.
</para> </para>
<programlisting><![CDATA[from eg.Cat as fatcat <programlisting><![CDATA[from Cat as fatcat
where fatcat.weight > ( where fatcat.weight > (
select avg(cat.weight) from eg.DomesticCat cat select avg(cat.weight) from DomesticCat cat
) )]]></programlisting>
from eg.DomesticCat as cat <programlisting><![CDATA[from DomesticCat as cat
where cat.name = some ( where cat.name = some (
select name.nickName from eg.Name as name select name.nickName from Name as name
) )]]></programlisting>
from eg.Cat as cat <programlisting><![CDATA[from Cat as cat
where not exists ( where not exists (
from eg.Cat as mate where mate.mate = cat from Cat as mate where mate.mate = cat
) )]]></programlisting>
from eg.DomesticCat as cat <programlisting><![CDATA[from DomesticCat as cat
where cat.name not in ( where cat.name not in (
select name.nickName from eg.Name as name select name.nickName from Name as name
)]]></programlisting> )]]></programlisting>
</sect1> </sect1>

View File

@ -86,7 +86,7 @@
"from cat_log cat where {cat.mate} = :catId" "from cat_log cat where {cat.mate} = :catId"
List loggedCats = sess.createSQLQuery(sql) List loggedCats = sess.createSQLQuery(sql)
.addEntity("cat", Cat.class) .addEntity("cat", Cat.class)
.setLong("catId", catId) .setLong("catId", catId)
.list();]]></programlisting> .list();]]></programlisting>
@ -138,14 +138,14 @@ List loggedCats = sess.createSQLQuery(sql)
</para> </para>
<sect2 id="propertyresults"> <sect2 id="propertyresults">
<title>Using property-result to explicitly specify column/alias names</title> <title>Using property-result to explicitly specify column/alias names</title>
<para> <para>
With <literal>&lt;property-result&gt;</literal> you can explicitly tell Hibernate what columns With <literal>&lt;property-result&gt;</literal> you can explicitly tell Hibernate what columns
to use as opposed to use <literal>{}</literal>-syntax to let Hibernate inject its own aliases. to use as opposed to use <literal>{}</literal>-syntax to let Hibernate inject its own aliases.
</para> </para>
<programlisting><![CDATA[<sql-query name="mySqlQuery"> <programlisting><![CDATA[<sql-query name="mySqlQuery">
<return alias="person" class="eg.Person"> <return alias="person" class="eg.Person">
<property-result name="name" column="myName"/> <property-result name="name" column="myName"/>
<property-result name="age" column="myAge"/> <property-result name="age" column="myAge"/>
@ -157,18 +157,18 @@ List loggedCats = sess.createSQLQuery(sql)
FROM PERSON person WHERE person.NAME LIKE :name FROM PERSON person WHERE person.NAME LIKE :name
</sql-query> </sql-query>
]]></programlisting> ]]></programlisting>
<literal>&lt;property-result&gt;</literal> also works with multiple columns. This solves a limitation with <literal>&lt;property-result&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. the <literal>{}</literal>-syntax which can not allow fine grained control of multi-column properties.
<programlisting><![CDATA[<sql-query name="organizationCurrentEmployments"> <programlisting><![CDATA[<sql-query name="organizationCurrentEmployments">
<return alias="emp" class="Employment"> <return alias="emp" class="Employment">
<property-result name="salary"> <property-result name="salary">
<result-column name="VALUE"/> <result-column name="VALUE"/>
<result-column name="CURRENCY"/> <result-column name="CURRENCY"/>
</property-result> </property-result>
<property-result name="endDate" column="myEndDate"/> <property-result name="endDate" column="myEndDate"/>
</return> </return>
SELECT EMPLOYEE AS {emp.employee}, EMPLOYER AS {emp.employer}, SELECT EMPLOYEE AS {emp.employee}, EMPLOYER AS {emp.employer},
STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate}, STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate},
REGIONCODE as {emp.regionCode}, EID AS {emp.id}, VALUE, CURRENCY REGIONCODE as {emp.regionCode}, EID AS {emp.id}, VALUE, CURRENCY
@ -176,29 +176,29 @@ List loggedCats = sess.createSQLQuery(sql)
WHERE EMPLOYER = :id AND ENDDATE IS NULL WHERE EMPLOYER = :id AND ENDDATE IS NULL
ORDER BY STARTDATE ASC ORDER BY STARTDATE ASC
</sql-query>]]></programlisting> </sql-query>]]></programlisting>
<para> <para>
Notice that in this example we used <literal>&lt;property-result&gt;</literal> in combination Notice that in this example we used <literal>&lt;property-result&gt;</literal> in combination
with the <literal>{}</literal>-syntax for injection. Allowing users to choose with the <literal>{}</literal>-syntax for injection. Allowing users to choose
how they want to refer column and properties. how they want to refer column and properties.
</para> </para>
<para> <para>
If your mapping has a discriminator you must use &lt;discriminator-result&gt; to specify the discriminators column. If your mapping has a discriminator you must use &lt;discriminator-result&gt; to specify the discriminators column.
</para> </para>
</sect2> </sect2>
<sect2 id="sp_query"> <sect2 id="sp_query">
<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. The stored procedures must return a resultset as the first out-parameter to be able to work with Hibernate.
An example of such a stored procedure in Oracle 9 and higher is as follows: 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
AS AS
st_cursor SYS_REFCURSOR; st_cursor SYS_REFCURSOR;
@ -208,57 +208,88 @@ BEGIN
STARTDATE, ENDDATE, STARTDATE, ENDDATE,
REGIONCODE, EID, VALUE, CURRENCY REGIONCODE, EID, VALUE, CURRENCY
FROM EMPLOYMENT; FROM EMPLOYMENT;
RETURN st_cursor; RETURN st_cursor;
END;]]></programlisting> END;]]></programlisting>
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.
<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">
<property-result name="employee" column="EMPLOYEE"/> <property-result name="employee" column="EMPLOYEE"/>
<property-result name="employer" column="EMPLOYER"/> <property-result name="employer" column="EMPLOYER"/>
<property-result name="startDate" column="STARTDATE"/> <property-result name="startDate" column="STARTDATE"/>
<property-result name="endDate" column="ENDDATE"/> <property-result name="endDate" column="ENDDATE"/>
<property-result name="regionCode" column="REGIONCODE"/> <property-result name="regionCode" column="REGIONCODE"/>
<property-result name="id" column="EID"/> <property-result name="id" column="EID"/>
<property-result name="salary"> <property-result name="salary">
<result-column name="VALUE"/> <result-column name="VALUE"/>
<result-column name="CURRENCY"/> <result-column name="CURRENCY"/>
</property-result> </property-result>
</return> </return>
{ ? = call selectAllEmployments() } { ? = call selectAllEmployments() }
</sql-query>]]></programlisting> </sql-query>]]></programlisting>
</para> </para>
<para> <para>
Notice stored procedures currently only return scalars and entities. <literal>&gt;return-join&lt;</literal> and Notice stored procedures currently only return scalars and entities.
<literal>&gt;load-collection&lt;</literal> is not supported. <literal>&lt;return-join&gt;</literal> and <literal>&lt;load-collection&gt;</literal>
</para> are not supported.
</para>
<para>
TODO: make the "rules" visually nicer and understandable ,) <para>
</para> TODO: make the "rules" visually nicer and understandable ,)
</para>
<sect3>
<title>Rules/Limitations for using stored procedures</title> <sect3>
<title>Rules/Limitations for using stored procedures</title>
<para>
To use stored procedures with Hibernate the procedures have to follow some rules. If they do not follow those <para>
rules they are not usable with Hibernate. If you still want to use these procedures you have to execute them via <literal>session.connection()</literal>. To use stored procedures with Hibernate the procedures have to follow some rules.
If they do not follow those rules they are not usable with Hibernate. If you still
The rules are different per database since database vendors have different stored procedure semantics/syntax. want to use these procedures you have to execute them via <literal>session.connection()</literal>.
The rules are different per database since database vendors have different stored procedure
For Oracle the following rules applies: semantics/syntax.
</para>
1. It must return a result set. (This is done by returning a SYS_REFCURSOR in Oracle 9 & 10, in Oracle you need to define a REF CURSOR type)
2. It should be on the form <literal>{ ? = call procName(<parameters>) }</literal> or <literal>{ ? = call procName}</literal> (this is more a Oracle rule than a Hibernate rule) <para>
For Oracle the following rules apply:
For Sybase & MS SQL server the following rules applies: </para>
It must return a result set. Note that since these servers can/will return multiple result sets and update count Hibernate will iterate the results and take the first result that is a result set as its return value. Everything else will be discarded. <itemizedlist spacing="compact">
If you can enable SET NOCOUNT ON in your procedure it will probably be the most efficient, but it is not an requirement. <listitem>
</para> <para>
</sect3> It must return a result set. This is done by returning a SYS_REFCURSOR in Oracle 9 or 10.
In Oracle you need to define a REF CURSOR type.
</para>
</listitem>
<listitem>
<para>
It should be on the form <literal>{ ? = call procName(&lt;parameters&gt;) }</literal> or
<literal>{ ? = call procName }</literal> (This is more an Oracle rule than a Hibernate rule.)
</para>
</listitem>
</itemizedlist>
<para>
For Sybase or MS SQL server the following rules apply:
</para>
<itemizedlist spacing="compact">
<listitem>
<para>
It must return a result set. Note that since these servers can/will return multiple result
sets and update count Hibernate will iterate the results and take the first result that is
a result set as its return value. Everything else will be discarded.
</para>
</listitem>
<listitem>
<para>
If you can enable SET NOCOUNT ON in your procedure it will probably be the most efficient, but
it is not a requirement.
</para>
</listitem>
</itemizedlist>
</sect3>
</sect2> </sect2>
</sect1> </sect1>
@ -304,16 +335,16 @@ BEGIN
<sql-update callable="true">{? = call updatePerson (?, ?)}</sql-update> <sql-update callable="true">{? = call updatePerson (?, ?)}</sql-update>
</class>]]></programlisting> </class>]]></programlisting>
<para> <para>
The order of the positional parameters are currently vital, as they must be in The order of the positional parameters are currently vital, as they must be in
the same sequence as Hibernate expects them. the same sequence as Hibernate expects them.
</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 <literal>org.hiberante.persister.entity</literal>
level. With this level enabled Hibernate will print out the static SQL that is used to create, update, delete etc. entities. level. With this level enabled 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. 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>
The stored procedures are in most cases (read: better do it than not) required to The stored procedures are in most cases (read: better do it than not) required to
@ -336,7 +367,7 @@ BEGIN
END updatePerson;]]></programlisting> END updatePerson;]]></programlisting>
</sect1> </sect1>
<sect1 id="querysql-load"> <sect1 id="querysql-load">
@ -363,10 +394,10 @@ END updatePerson;]]></programlisting>
<property name="name" not-null="true"/> <property name="name" not-null="true"/>
<loader query-ref="person"/> <loader query-ref="person"/>
</class>]]></programlisting> </class>]]></programlisting>
<para> <para>
And this also works with stored procedures. And this also works with stored procedures.
</para> </para>
<para> <para>
TODO: Document the following example for collection loader. TODO: Document the following example for collection loader.