Hibernate SVN: r10853 - trunk/Hibernate3/test/org/hibernate/test
by hibernate-commits@lists.jboss.org
Author: steve.ebersole(a)jboss.com
Date: 2006-11-21 12:42:38 -0500 (Tue, 21 Nov 2006)
New Revision: 10853
Modified:
trunk/Hibernate3/test/org/hibernate/test/AllTests.java
Log:
HHH-1851 : add tests to AllTests
Modified: trunk/Hibernate3/test/org/hibernate/test/AllTests.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/AllTests.java 2006-11-21 17:39:14 UTC (rev 10852)
+++ trunk/Hibernate3/test/org/hibernate/test/AllTests.java 2006-11-21 17:42:38 UTC (rev 10853)
@@ -50,6 +50,7 @@
import org.hibernate.test.id.MultipleHiLoPerTableGeneratorTest;
import org.hibernate.test.idbag.IdBagTest;
import org.hibernate.test.idclass.IdClassTest;
+import org.hibernate.test.idprops.IdentifierPropertyReferencesTest;
import org.hibernate.test.immutable.ImmutableTest;
import org.hibernate.test.instrument.buildtime.InstrumentTest;
import org.hibernate.test.instrument.runtime.CGLIBInstrumentationTest;
@@ -292,6 +293,7 @@
suite.addTest( AnyTypeTest.suite() );
suite.addTest( SQLFunctionsInterSystemsTest.suite() );
suite.addTest( LobSuite.suite() );
+ suite.addTest( IdentifierPropertyReferencesTest.suite() );
return filter( suite );
//return suite;
18 years, 1 month
Hibernate SVN: r10852 - in trunk/Hibernate3: doc/reference/en/modules src/org/hibernate/hql/ast/tree src/org/hibernate/persister/entity src/org/hibernate/tuple/entity test/org/hibernate/test test/org/hibernate/test/idprops test/org/hibernate/test/legacy
by hibernate-commits@lists.jboss.org
Author: steve.ebersole(a)jboss.com
Date: 2006-11-21 12:39:14 -0500 (Tue, 21 Nov 2006)
New Revision: 10852
Added:
trunk/Hibernate3/test/org/hibernate/test/idprops/
trunk/Hibernate3/test/org/hibernate/test/idprops/IdentifierPropertyReferencesTest.java
trunk/Hibernate3/test/org/hibernate/test/idprops/LineItem.java
trunk/Hibernate3/test/org/hibernate/test/idprops/LineItemPK.java
trunk/Hibernate3/test/org/hibernate/test/idprops/Mapping.hbm.xml
trunk/Hibernate3/test/org/hibernate/test/idprops/Order.java
trunk/Hibernate3/test/org/hibernate/test/idprops/Person.java
Modified:
trunk/Hibernate3/doc/reference/en/modules/query_hql.xml
trunk/Hibernate3/src/org/hibernate/hql/ast/tree/DotNode.java
trunk/Hibernate3/src/org/hibernate/hql/ast/tree/FromElement.java
trunk/Hibernate3/src/org/hibernate/persister/entity/AbstractEntityPersister.java
trunk/Hibernate3/src/org/hibernate/persister/entity/AbstractPropertyMapping.java
trunk/Hibernate3/src/org/hibernate/persister/entity/EntityPersister.java
trunk/Hibernate3/src/org/hibernate/tuple/entity/EntityMetamodel.java
trunk/Hibernate3/test/org/hibernate/test/legacy/CustomPersister.java
Log:
HHH-1851 : relax special 'id' property handling
Modified: trunk/Hibernate3/doc/reference/en/modules/query_hql.xml
===================================================================
--- trunk/Hibernate3/doc/reference/en/modules/query_hql.xml 2006-11-21 17:38:43 UTC (rev 10851)
+++ trunk/Hibernate3/doc/reference/en/modules/query_hql.xml 2006-11-21 17:39:14 UTC (rev 10852)
@@ -1,6 +1,6 @@
-<chapter id="queryhql">
+<chapter id="queryhql" revision="1">
<title>HQL: The Hibernate Query Language</title>
-
+
<para>
Hibernate is equipped with an extremely powerful query language that (quite intentionally)
looks very much like SQL. But don't be fooled by the syntax; HQL is fully object-oriented,
@@ -20,12 +20,12 @@
<literal>foo.barSet</literal> is not
<literal>foo.BARSET</literal>.
</para>
-
+
<para>
- This manual uses lowercase HQL keywords. Some users find queries with uppercase keywords
+ This manual uses lowercase HQL keywords. Some users find queries with uppercase keywords
more readable, but we find this convention ugly when embedded in Java code.
</para>
-
+
</sect1>
<sect1 id="queryhql-from">
@@ -34,17 +34,17 @@
<para>
The simplest possible Hibernate query is of the form:
</para>
-
+
<programlisting><![CDATA[from eg.Cat]]></programlisting>
-
+
<para>
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>
-
+
<programlisting><![CDATA[from Cat]]></programlisting>
-
+
<para>
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
@@ -58,33 +58,33 @@
instances, so we could use that alias later in the query. The <literal>as</literal>
keyword is optional; we could also write:
</para>
-
+
<programlisting><![CDATA[from Cat cat]]></programlisting>
-
+
<para>
Multiple classes may appear, resulting in a cartesian product or "cross" join.
</para>
-
+
<programlisting><![CDATA[from Formula, Parameter]]></programlisting>
<programlisting><![CDATA[from Formula as form, Parameter as param]]></programlisting>
-
+
<para>
It is considered good practice to name query aliases using an initial lowercase,
consistent with Java naming standards for local variables
(eg. <literal>domesticCat</literal>).
</para>
-
+
</sect1>
<sect1 id="queryhql-joins" revision="2">
<title>Associations and joins</title>
<para>
- We may also assign aliases to associated entities, or even to elements of a
+ We may also assign aliases to associated entities, or even to elements of a
collection of values, using a <literal>join</literal>.
</para>
- <programlisting><![CDATA[from Cat as cat
+ <programlisting><![CDATA[from Cat as cat
inner join cat.mate as mate
left outer join cat.kittens as kitten]]></programlisting>
@@ -118,50 +118,50 @@
</para>
</listitem>
</itemizedlist>
-
+
<para>
- The <literal>inner join</literal>, <literal>left outer join</literal> and
+ The <literal>inner join</literal>, <literal>left outer join</literal> and
<literal>right outer join</literal> constructs may be abbreviated.
</para>
- <programlisting><![CDATA[from Cat as cat
+ <programlisting><![CDATA[from Cat as cat
join cat.mate as mate
left join cat.kittens as kitten]]></programlisting>
-
+
<para>
You may supply extra join conditions using the HQL <literal>with</literal>
keyword.
</para>
- <programlisting><![CDATA[from Cat as cat
- left join cat.kittens as kitten
+ <programlisting><![CDATA[from Cat as cat
+ left join cat.kittens as kitten
with kitten.bodyWeight > 10.0]]></programlisting>
<para>
- In addition, a "fetch" join allows associations or collections of values to be
- initialized along with their parent objects, using a single select. This is particularly
+ In addition, a "fetch" join allows associations or collections of values to be
+ initialized along with their parent objects, using a single select. This is particularly
useful in the case of a collection. It effectively overrides the outer join and
lazy declarations of the mapping file for associations and collections. See
<xref linkend="performance-fetching"/> for more information.
</para>
-
- <programlisting><![CDATA[from Cat as cat
+
+ <programlisting><![CDATA[from Cat as cat
inner join fetch cat.mate
left join fetch cat.kittens]]></programlisting>
-
+
<para>
- A fetch join does not usually need to assign an alias, because the associated objects
- should not be used in the <literal>where</literal> clause (or any other clause). Also,
- the associated objects are not returned directly in the query results. Instead, they may
+ A fetch join does not usually need to assign an alias, because the associated objects
+ should not be used in the <literal>where</literal> clause (or any other clause). Also,
+ the associated objects are not returned directly in the query results. Instead, they may
be accessed via the parent object. The only reason we might need an alias is if we are
recursively join fetching a further collection:
</para>
-
- <programlisting><![CDATA[from Cat as cat
+
+ <programlisting><![CDATA[from Cat as cat
inner join fetch cat.mate
left join fetch cat.kittens child
left join fetch child.kittens]]></programlisting>
-
+
<para>
Note that the <literal>fetch</literal> construct may not be used in queries called using
<literal>iterate()</literal> (though <literal>scroll()</literal> can be used). Nor should
@@ -171,18 +171,18 @@
you'd expect.
Nor may <literal>fetch</literal> be used together with an ad hoc <literal>with</literal> condition.
It is possible to create a cartesian product by join fetching more than one collection in a
- query, so take care in this case. Join fetching multiple collection roles also sometimes gives
- unexpected results for bag mappings, so be careful about how you formulate your queries in this
- case. Finally, note that <literal>full join fetch</literal> and <literal>right join fetch</literal>
+ query, so take care in this case. Join fetching multiple collection roles also sometimes gives
+ unexpected results for bag mappings, so be careful about how you formulate your queries in this
+ case. Finally, note that <literal>full join fetch</literal> and <literal>right join fetch</literal>
are not meaningful.
</para>
-
+
<para>
If you are using property-level lazy fetching (with bytecode instrumentation), it is
possible to force Hibernate to fetch the lazy properties immediately (in the first
query) using <literal>fetch all properties</literal>.
</para>
-
+
<programlisting><![CDATA[from Document fetch all properties order by name]]></programlisting>
<programlisting><![CDATA[from Document doc fetch all properties where lower(doc.name) like '%cats%']]></programlisting>
@@ -210,16 +210,52 @@
<programlisting><![CDATA[from Cat as cat where cat.mate.name like '%s%']]></programlisting>
</sect1>
+ <sect1 id="queryhql-identifier-property">
+ <title>Refering to identifier property</title>
+
+ <para>
+ There are, generally speaking, 2 ways to refer to an entity's identifier property:
+ </para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ The special property (lowercase) <literal>id</literal> may be used to reference the identifier
+ property of an entity <emphasis>provided that entity does not define a non-identifier property
+ named id</emphasis>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ If the entity defines a named identifier property, you may use that property name.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ References to composite identifier properties follow the same naming rules. If the
+ entity has a non-identifier property named id, the composite identifier property can only
+ be referenced by its defined named; otherwise, the special <literal>id</literal> property
+ can be used to rerference the identifier property.
+ </para>
+
+ <para>
+ Note: this has changed significantly starting in version 3.2.2. In previous versions,
+ <literal>id</literal> <emphasis>always</emphasis> referred to the identifier property no
+ matter what its actual name. A ramification of that decision was that non-identifier
+ properties named <literal>id</literal> could never be referenced in Hibernate queries.
+ </para>
+ </sect1>
+
<sect1 id="queryhql-select">
<title>The select clause</title>
<para>
- The <literal>select</literal> clause picks which objects and properties to return in
+ The <literal>select</literal> clause picks which objects and properties to return in
the query result set. Consider:
</para>
- <programlisting><![CDATA[select mate
-from Cat as cat
+ <programlisting><![CDATA[select mate
+from Cat as cat
inner join cat.mate as mate]]></programlisting>
<para>
@@ -239,37 +275,37 @@
<programlisting><![CDATA[select cust.name.firstName from Customer as cust]]></programlisting>
<para>
- Queries may return multiple objects and/or properties as an array of type
+ Queries may return multiple objects and/or properties as an array of type
<literal>Object[]</literal>,
</para>
- <programlisting><![CDATA[select mother, offspr, mate.name
+ <programlisting><![CDATA[select mother, offspr, mate.name
from DomesticCat as mother
inner join mother.mate as mate
left outer join mother.kittens as offspr]]></programlisting>
-
+
<para>
or as a <literal>List</literal>,
</para>
-
+
<programlisting><![CDATA[select new list(mother, offspr, mate.name)
from DomesticCat as mother
inner join mother.mate as mate
left outer join mother.kittens as offspr]]></programlisting>
-
+
<para>
or as an actual typesafe Java object,
</para>
-
+
<programlisting><![CDATA[select new Family(mother, mate, offspr)
from DomesticCat as mother
join mother.mate as mate
left join mother.kittens as offspr]]></programlisting>
-
+
<para>
assuming that the class <literal>Family</literal> has an appropriate constructor.
</para>
-
+
<para>
You may assign aliases to selected expressions using <literal>as</literal>:
</para>
@@ -280,14 +316,14 @@
<para>
This is most useful when used together with <literal>select new map</literal>:
</para>
-
+
<programlisting><![CDATA[select new map( max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n )
from Cat cat]]></programlisting>
<para>
This query returns a <literal>Map</literal> from aliases to selected values.
</para>
-
+
</sect1>
<sect1 id="queryhql-aggregation">
@@ -302,11 +338,11 @@
<!-- NO LONGER SUPPORTED
<para>
- Collections may also appear inside aggregate functions in the <literal>select</literal>
+ Collections may also appear inside aggregate functions in the <literal>select</literal>
clause.
</para>
- <programlisting><![CDATA[select cat, count( elements(cat.kittens) )
+ <programlisting><![CDATA[select cat, count( elements(cat.kittens) )
from Cat cat group by cat]]></programlisting>
-->
@@ -331,21 +367,21 @@
</para>
</listitem>
</itemizedlist>
-
+
<para>
You may use arithmetic operators, concatenation, and recognized SQL functions
in the select clause:
</para>
-
- <programlisting><![CDATA[select cat.weight + sum(kitten.weight)
-from Cat cat
+
+ <programlisting><![CDATA[select cat.weight + sum(kitten.weight)
+from Cat cat
join cat.kittens kitten
group by cat.id, cat.weight]]></programlisting>
-
+
<programlisting><![CDATA[select firstName||' '||initial||' '||upper(lastName) from Person]]></programlisting>
-
+
<para>
- The <literal>distinct</literal> and <literal>all</literal> keywords may be used and
+ The <literal>distinct</literal> and <literal>all</literal> keywords may be used and
have the same semantics as in SQL.
</para>
@@ -354,7 +390,7 @@
select count(distinct cat.name), count(cat) from Cat cat]]></programlisting>
</sect1>
-
+
<sect1 id="queryhql-polymorphism">
<title>Polymorphic queries</title>
@@ -366,30 +402,30 @@
<para>
returns instances not only of <literal>Cat</literal>, but also of subclasses like
- <literal>DomesticCat</literal>. Hibernate queries may name <emphasis>any</emphasis> Java
- class or interface in the <literal>from</literal> clause. The query will return instances
- of all persistent classes that extend that class or implement the interface. The following
+ <literal>DomesticCat</literal>. Hibernate queries may name <emphasis>any</emphasis> Java
+ class or interface in the <literal>from</literal> clause. The query will return instances
+ of all persistent classes that extend that class or implement the interface. The following
query would return all persistent objects:
</para>
-
+
<programlisting><![CDATA[from java.lang.Object o]]></programlisting>
-
+
<para>
The interface <literal>Named</literal> might be implemented by various persistent
classes:
</para>
-
+
<programlisting><![CDATA[from Named n, Named m where n.name = m.name]]></programlisting>
-
+
<para>
Note that these last two queries will require more than one SQL <literal>SELECT</literal>. This
means that the <literal>order by</literal> clause does not correctly order the whole result set.
(It also means you can't call these queries using <literal>Query.scroll()</literal>.)
</para>
-
+
</sect1>
- <sect1 id="queryhql-where">
+ <sect1 id="queryhql-where" revision="1">
<title>The where clause</title>
<para>
@@ -398,18 +434,18 @@
</para>
<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>
returns instances of <literal>Cat</literal> named 'Fritz'.
</para>
- <programlisting><![CDATA[select foo
+ <programlisting><![CDATA[select foo
from Foo foo, Bar bar
where foo.startDate = bar.date]]></programlisting>
@@ -429,7 +465,7 @@
something like
</para>
- <programlisting><![CDATA[from Foo foo
+ <programlisting><![CDATA[from Foo foo
where foo.bar.baz.customer.address.city is not null]]></programlisting>
<para>
@@ -437,19 +473,20 @@
</para>
<para>
- The <literal>=</literal> operator may be used to compare not only properties, but also
+ The <literal>=</literal> operator may be used to compare not only properties, but also
instances:
</para>
<programlisting><![CDATA[from Cat cat, Cat rival where cat.mate = rival.mate]]></programlisting>
- <programlisting><![CDATA[select cat, mate
+ <programlisting><![CDATA[select cat, mate
from Cat cat, Cat mate
where cat.mate = mate]]></programlisting>
<para>
- The special property (lowercase) <literal>id</literal> may be used to reference the
- unique identifier of an object. (You may also use its property name.)
+ The special property (lowercase) <literal>id</literal> may be used to reference the
+ unique identifier of an object. See <xref linkend="queryhql-identifier-property"/>
+ for more information.
</para>
<programlisting><![CDATA[from Cat as cat where cat.id = 123
@@ -461,55 +498,51 @@
</para>
<para>
- Properties of composite identifiers may also be used. Suppose <literal>Person</literal>
- has a composite identifier consisting of <literal>country</literal> and
- <literal>medicareNumber</literal>.
+ Properties of composite identifiers may also be used. Suppose <literal>Person</literal>
+ has a composite identifier consisting of <literal>country</literal> and
+ <literal>medicareNumber</literal>. Again, see <xref linkend="queryhql-identifier-property"/>
+ for more information regarding referencing identifier properties.
</para>
<programlisting><![CDATA[from bank.Person person
-where person.id.country = 'AU'
+where person.id.country = 'AU'
and person.id.medicareNumber = 123456]]></programlisting>
<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>
<para>
Once again, the second query requires no table join.
</para>
-
+
<para>
Likewise, the special property <literal>class</literal> accesses the discriminator value
- of an instance in the case of polymorphic persistence. A Java class name embedded in the
+ of an instance in the case of polymorphic persistence. A Java class name embedded in the
where clause will be translated to its discriminator value.
</para>
<programlisting><![CDATA[from Cat cat where cat.class = DomesticCat]]></programlisting>
-
+
<para>
- You may also specify properties of components or composite user types (and of components
- of components, etc). Never try to use a path-expression that ends in a property of component
- type (as opposed to a property of a component). For example, if <literal>store.owner</literal>
- is an entity with a component <literal>address</literal>
+ You may also use components or composite user types, or properties of said
+ component types. See <xref linkend="queryhql-coomponents"/> for more details.
</para>
- <programlisting><![CDATA[store.owner.address.city // okay
-store.owner.address // error!]]></programlisting>
-
<para>
An "any" type has the special properties <literal>id</literal> and <literal>class</literal>,
allowing us to express a join in the following way (where <literal>AuditLog.item</literal>
is a property mapped with <literal><any></literal>).
</para>
-
- <programlisting><![CDATA[from AuditLog log, Payment payment
+
+ <programlisting><![CDATA[from AuditLog log, Payment payment
where log.item.class = 'Payment' and log.item.id = payment.id]]></programlisting>
-
+
<para>
Notice that <literal>log.item.class</literal> and <literal>payment.class</literal>
would refer to the values of completely different database columns in the above query.
</para>
-
+
</sect1>
<sect1 id="queryhql-expressions">
@@ -550,14 +583,14 @@
<literal>is not null</literal>,
<literal>is empty</literal>,
<literal>is not empty</literal>,
- <literal>member of</literal> and
+ <literal>member of</literal> and
<literal>not member of</literal>
</para>
</listitem>
<listitem>
<para>
"Simple" case, <literal>case ... when ... then ... else ... end</literal>, and
- "searched" case, <literal>case when ... then ... else ... end</literal>
+ "searched" case, <literal>case when ... then ... else ... end</literal>
</para>
</listitem>
<listitem>
@@ -573,8 +606,8 @@
</listitem>
<listitem>
<para>
- <literal>second(...)</literal>, <literal>minute(...)</literal>,
- <literal>hour(...)</literal>, <literal>day(...)</literal>,
+ <literal>second(...)</literal>, <literal>minute(...)</literal>,
+ <literal>hour(...)</literal>, <literal>day(...)</literal>,
<literal>month(...)</literal>, <literal>year(...)</literal>,
</para>
</listitem>
@@ -592,14 +625,14 @@
<listitem>
<para>
<literal>str()</literal> for converting numeric or temporal values to a
- readable string
+ readable string
</para>
</listitem>
<listitem>
<para>
<literal>cast(... as ...)</literal>, where the second argument is the name of
- a Hibernate type, and <literal>extract(... from ...)</literal> if ANSI
- <literal>cast()</literal> and <literal>extract()</literal> is supported by
+ a Hibernate type, and <literal>extract(... from ...)</literal> if ANSI
+ <literal>cast()</literal> and <literal>extract()</literal> is supported by
the underlying database
</para>
</listitem>
@@ -611,15 +644,15 @@
</listitem>
<listitem>
<para>
- HQL functions that take collection-valued path expressions: <literal>size(),
- minelement(), maxelement(), minindex(), maxindex()</literal>, along with the
+ HQL functions that take collection-valued path expressions: <literal>size(),
+ minelement(), maxelement(), minindex(), maxindex()</literal>, along with the
special <literal>elements()</literal> and <literal>indices</literal> functions
which may be quantified using <literal>some, all, exists, any, in</literal>.
</para>
</listitem>
<listitem>
<para>
- Any database-supported SQL scalar function like <literal>sign()</literal>,
+ Any database-supported SQL scalar function like <literal>sign()</literal>,
<literal>trunc()</literal>, <literal>rtrim()</literal>, <literal>sin()</literal>
</para>
</listitem>
@@ -663,7 +696,7 @@
<programlisting><![CDATA[from DomesticCat cat where cat.name not in ( 'Foo', 'Bar', 'Baz' )]]></programlisting>
<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
for null values.
</para>
@@ -692,20 +725,20 @@
<para>
For indexed collections, you may refer to the minimum and maximum indices using
- <literal>minindex</literal> and <literal>maxindex</literal> functions. Similarly,
- you may refer to the minimum and maximum elements of a collection of basic type
+ <literal>minindex</literal> and <literal>maxindex</literal> functions. Similarly,
+ you may refer to the minimum and maximum elements of a collection of basic type
using the <literal>minelement</literal> and <literal>maxelement</literal>
functions.
</para>
-
+
<programlisting><![CDATA[from Calendar cal where maxelement(cal.holidays) > current_date]]></programlisting>
-
+
<programlisting><![CDATA[from Order order where maxindex(order.items) > 100]]></programlisting>
<programlisting><![CDATA[from Order order where minelement(order.items) > 10000]]></programlisting>
-
+
<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
or index set of a collection (<literal>elements</literal> and <literal>indices</literal> functions)
or the result of a subquery (see below).
</para>
@@ -728,12 +761,12 @@
<literal>minelement</literal>, <literal>maxelement</literal> - may only be used in
the where clause in Hibernate3.
</para>
-
+
<para>
Elements of indexed collections (arrays, lists, maps) may be referred to by
index (in a where clause only):
</para>
-
+
<programlisting><![CDATA[from Order order where order.items[0].id = 1234]]></programlisting>
<programlisting><![CDATA[select person from Person person, Calendar calendar
@@ -749,16 +782,16 @@
<para>
The expression inside <literal>[]</literal> may even be an arithmetic expression.
</para>
-
+
<programlisting><![CDATA[select item from Item item, Order order
where order.items[ size(order.items) - 1 ] = item]]></programlisting>
-
+
<para>
- HQL also provides the built-in <literal>index()</literal> function, for elements
+ HQL also provides the built-in <literal>index()</literal> function, for elements
of a one-to-many association or collection of values.
</para>
- <programlisting><![CDATA[select item, index(item) from Order order
+ <programlisting><![CDATA[select item, index(item) from Order order
join order.items item
where index(item) < 5]]></programlisting>
@@ -769,7 +802,7 @@
<programlisting><![CDATA[from DomesticCat cat where upper(cat.name) like 'FRI%']]></programlisting>
<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
following query would be in SQL:
</para>
@@ -816,7 +849,7 @@
order by cat.name asc, cat.weight desc, cat.birthdate]]></programlisting>
<para>
- The optional <literal>asc</literal> or <literal>desc</literal> indicate ascending or descending order
+ The optional <literal>asc</literal> or <literal>desc</literal> indicate ascending or descending order
respectively.
</para>
</sect1>
@@ -828,11 +861,11 @@
A query that returns aggregate values may be grouped by any property of a returned class or components:
</para>
- <programlisting><![CDATA[select cat.color, sum(cat.weight), count(cat)
+ <programlisting><![CDATA[select cat.color, sum(cat.weight), count(cat)
from Cat cat
group by cat.color]]></programlisting>
- <programlisting><![CDATA[select foo.id, avg(name), max(name)
+ <programlisting><![CDATA[select foo.id, avg(name), max(name)
from Foo foo join foo.names name
group by foo.id]]></programlisting>
@@ -840,14 +873,14 @@
A <literal>having</literal> clause is also allowed.
</para>
- <programlisting><![CDATA[select cat.color, sum(cat.weight), count(cat)
+ <programlisting><![CDATA[select cat.color, sum(cat.weight), count(cat)
from Cat cat
-group by cat.color
+group by cat.color
having cat.color in (eg.Color.TABBY, eg.Color.BLACK)]]></programlisting>
<para>
SQL functions and aggregate functions are allowed in the <literal>having</literal>
- and <literal>order by</literal> clauses, if supported by the underlying database
+ and <literal>order by</literal> clauses, if supported by the underlying database
(eg. not in MySQL).
</para>
@@ -868,37 +901,37 @@
</para>
</sect1>
-
- <sect1 id="queryhql-subqueries" revision="2">
+
+ <sect1 id="queryhql-subqueries" revision="3">
<title>Subqueries</title>
-
+
<para>
For databases that support subselects, Hibernate supports subqueries within queries. A subquery must
be surrounded by parentheses (often by an SQL aggregate function call). Even correlated subqueries
(subqueries that refer to an alias in the outer query) are allowed.
</para>
- <programlisting><![CDATA[from Cat as fatcat
-where fatcat.weight > (
- select avg(cat.weight) from DomesticCat cat
+ <programlisting><![CDATA[from Cat as fatcat
+where fatcat.weight > (
+ select avg(cat.weight) from DomesticCat cat
)]]></programlisting>
- <programlisting><![CDATA[from DomesticCat as cat
-where cat.name = some (
- select name.nickName from Name as name
+ <programlisting><![CDATA[from DomesticCat as cat
+where cat.name = some (
+ select name.nickName from Name as name
)]]></programlisting>
-
- <programlisting><![CDATA[from Cat as cat
-where not exists (
- from Cat as mate where mate.mate = cat
+
+ <programlisting><![CDATA[from Cat as cat
+where not exists (
+ from Cat as mate where mate.mate = cat
)]]></programlisting>
- <programlisting><![CDATA[from DomesticCat as cat
-where cat.name not in (
- select name.nickName from Name as name
+ <programlisting><![CDATA[from DomesticCat as cat
+where cat.name not in (
+ select name.nickName from Name as name
)]]></programlisting>
- <programlisting><![CDATA[select cat.id, (select max(kit.weight) from cat.kitten kit)
+ <programlisting><![CDATA[select cat.id, (select max(kit.weight) from cat.kitten kit)
from Cat as cat]]></programlisting>
<para>
@@ -906,53 +939,30 @@
</para>
<para>
- For subqueries with more than one expression in the select list, you can use a tuple constructor:
+ Note that subqueries can also utilize <literal>row value constructor</literal> syntax. See
+ <xref linkend="queryhql-tuple"/> for more details.
</para>
-
- <programlisting><![CDATA[from Cat as cat
-where not ( cat.name, cat.color ) in (
- select cat.name, cat.color from DomesticCat cat
-)]]></programlisting>
- <para>
- Note that on some databases (but not Oracle or HSQL), you can use tuple constructors in other
- contexts, for example when querying components or composite user types:
- </para>
-
- <programlisting><![CDATA[from Person where name = ('Gavin', 'A', 'King')]]></programlisting>
-
- <para>
- Which is equivalent to the more verbose:
- </para>
-
- <programlisting><![CDATA[from Person where name.first = 'Gavin' and name.initial = 'A' and name.last = 'King')]]></programlisting>
-
- <para>
- There are two good reasons you might not want to do this kind of thing: first, it is not
- completely portable between database platforms; second, the query is now dependent upon
- the ordering of properties in the mapping document.
- </para>
-
</sect1>
<sect1 id="queryhql-examples">
<title>HQL examples</title>
-
+
<para>
Hibernate queries can be quite powerful and complex. In fact, the power of the query language
is one of Hibernate's main selling points. Here are some example queries very similar to queries
that I used on a recent project. Note that most queries you will write are much simpler than these!
</para>
-
+
<para>
- The following query returns the order id, number of items and total value of the order for all
- unpaid orders for a particular customer and given minimum total value, ordering the results by
- total value. In determining the prices, it uses the current catalog. The resulting SQL query,
+ The following query returns the order id, number of items and total value of the order for all
+ unpaid orders for a particular customer and given minimum total value, ordering the results by
+ total value. In determining the prices, it uses the current catalog. The resulting SQL query,
against the <literal>ORDER</literal>, <literal>ORDER_LINE</literal>, <literal>PRODUCT</literal>,
<literal>CATALOG</literal> and <literal>PRICE</literal> tables has four inner joins and an
(uncorrelated) subselect.
</para>
-
+
<programlisting><![CDATA[select order.id, sum(price.amount), count(item)
from Order as order
join order.lineItems as item
@@ -964,19 +974,19 @@
and price.product = product
and catalog.effectiveDate < sysdate
and catalog.effectiveDate >= all (
- select cat.effectiveDate
+ select cat.effectiveDate
from Catalog as cat
where cat.effectiveDate < sysdate
)
group by order
having sum(price.amount) > :minAmount
order by sum(price.amount) desc]]></programlisting>
-
+
<para>
- What a monster! Actually, in real life, I'm not very keen on subqueries, so my query was
+ What a monster! Actually, in real life, I'm not very keen on subqueries, so my query was
really more like this:
</para>
-
+
<programlisting><![CDATA[select order.id, sum(price.amount), count(item)
from Order as order
join order.lineItems as item
@@ -990,24 +1000,24 @@
group by order
having sum(price.amount) > :minAmount
order by sum(price.amount) desc]]></programlisting>
-
+
<para>
The next query counts the number of payments in each status, excluding all payments in the
- <literal>AWAITING_APPROVAL</literal> status where the most recent status change was made by the
- current user. It translates to an SQL query with two inner joins and a correlated subselect
- against the <literal>PAYMENT</literal>, <literal>PAYMENT_STATUS</literal> and
+ <literal>AWAITING_APPROVAL</literal> status where the most recent status change was made by the
+ current user. It translates to an SQL query with two inner joins and a correlated subselect
+ against the <literal>PAYMENT</literal>, <literal>PAYMENT_STATUS</literal> and
<literal>PAYMENT_STATUS_CHANGE</literal> tables.
</para>
- <programlisting><![CDATA[select count(payment), status.name
-from Payment as payment
+ <programlisting><![CDATA[select count(payment), status.name
+from Payment as payment
join payment.currentStatus as status
join payment.statusChanges as statusChange
where payment.status.name <> PaymentStatus.AWAITING_APPROVAL
or (
- statusChange.timeStamp = (
- select max(change.timeStamp)
- from PaymentStatusChange change
+ statusChange.timeStamp = (
+ select max(change.timeStamp)
+ from PaymentStatusChange change
where change.payment = payment
)
and statusChange.user <> :currentUser
@@ -1016,11 +1026,11 @@
order by status.sortOrder]]></programlisting>
<para>
- If I would have mapped the <literal>statusChanges</literal> collection as a list, instead of a set,
+ If I would have mapped the <literal>statusChanges</literal> collection as a list, instead of a set,
the query would have been much simpler to write.
</para>
-
- <programlisting><![CDATA[select count(payment), status.name
+
+ <programlisting><![CDATA[select count(payment), status.name
from Payment as payment
join payment.currentStatus as status
where payment.status.name <> PaymentStatus.AWAITING_APPROVAL
@@ -1031,9 +1041,9 @@
<para>
The next query uses the MS SQL Server <literal>isNull()</literal> function to return all
the accounts and unpaid payments for the organization to which the current user belongs.
- It translates to an SQL query with three inner joins, an outer join and a subselect against
+ It translates to an SQL query with three inner joins, an outer join and a subselect against
the <literal>ACCOUNT</literal>, <literal>PAYMENT</literal>, <literal>PAYMENT_STATUS</literal>,
- <literal>ACCOUNT_TYPE</literal>, <literal>ORGANIZATION</literal> and
+ <literal>ACCOUNT_TYPE</literal>, <literal>ORGANIZATION</literal> and
<literal>ORG_USER</literal> tables.
</para>
@@ -1082,7 +1092,7 @@
</para>
<programlisting><![CDATA[select usr.id, usr.name
-from User as usr
+from User as usr
left join usr.messages as msg
group by usr.id, usr.name
order by count(msg)]]></programlisting>
@@ -1135,7 +1145,7 @@
<para>
Collection elements may be ordered or grouped using a query filter:
</para>
-
+
<programlisting><![CDATA[Collection orderedCollection = s.filter( collection, "order by this.amount" );
Collection counts = s.filter( collection, "select this.type, count(this) group by this.type" );]]></programlisting>
@@ -1147,5 +1157,78 @@
</sect1>
+ <sect1 id="queryhql-components">
+ <title>Components</title>
+
+ <para>
+ Components might be used in just about every way that simple value types can be used in HQL
+ queries. They can appear in the <literal>select</literal> clause:
+ </para>
+
+ <programlisting><![CDATA[select p.name from from Person p]]></programlisting>
+ <programlisting><![CDATA[select p.name.first from from Person p]]></programlisting>
+
+ <para>
+ where the Person's name property is a component. Components can also be used
+ in the <literal>where</literal> clause:
+ </para>
+
+ <programlisting><![CDATA[from from Person p where p.name = :name]]></programlisting>
+ <programlisting><![CDATA[from from Person p where p.name.first = :firstName]]></programlisting>
+
+ <para>
+ Components can also be used in the <literal>order by</literal> clause:
+ </para>
+
+ <programlisting><![CDATA[from from Person p order by p.name]]></programlisting>
+ <programlisting><![CDATA[from from Person p order by p.name.first]]></programlisting>
+
+ <para>
+ Another common use of components is in <xref linkend="queryhql-tuple">row value constructors</xref>.
+ </para>
+ </sect1>
+
+ <sect1 id="queryhql-tuple">
+ <title>Row value constructor syntax</title>
+
+ <para>
+ HQL supports the use of ANSI SQL <literal>row value constructor</literal> syntax (sometimes
+ called <literal>tuple</literal> syntax), even though the underlying database may not support
+ that notion. Here we are generally referring to multi-valued comparisons, typically associated
+ with components. Consider an entity Person which defines a name component:
+ </para>
+
+ <programlisting><![CDATA[from Person p where p.name.first='John' and p.name.last='Jingleheimer-Schmidt']]></programlisting>
+
+ <para>
+ That's valid syntax, although a little verbose. It be nice to make this a bit more concise and use
+ <literal>row value constructor</literal> syntax:
+ </para>
+
+ <programlisting><![CDATA[from Person p where p.name=('John', 'Jingleheimer-Schmidt')]]></programlisting>
+
+ <para>
+ It can also be useful to specify this in the <literal>select</literal> clause:
+ </para>
+
+ <programlisting><![CDATA[select p.name from from Person p]]></programlisting>
+
+ <para>
+ Another time using <literal>row value constructor</literal> syntax can be beneficial
+ is when using subqueries needing to compare against multiple values:
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat
+where not ( cat.name, cat.color ) in (
+ select cat.name, cat.color from DomesticCat cat
+)]]></programlisting>
+
+ <para>
+ One thing to consider when deciding if you want to use this syntax is that the query will
+ be dependent upon the ordering of the component sub-properties in the metadata.
+ </para>
+
+ </sect1>
+
</chapter>
Modified: trunk/Hibernate3/src/org/hibernate/hql/ast/tree/DotNode.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/hql/ast/tree/DotNode.java 2006-11-21 17:38:43 UTC (rev 10851)
+++ trunk/Hibernate3/src/org/hibernate/hql/ast/tree/DotNode.java 2006-11-21 17:39:14 UTC (rev 10852)
@@ -81,9 +81,9 @@
private FromElement impliedJoin;
/**
- * Sets the join type for the '.' node (JoinFragment.XXX).
+ * Sets the join type for this '.' node structure.
*
- * @param joinType
+ * @param joinType The type of join to use.
* @see JoinFragment
*/
public void setJoinType(int joinType) {
@@ -220,8 +220,7 @@
private Type prepareLhs() throws SemanticException {
FromReferenceNode lhs = getLhs();
lhs.prepareForDot( propertyName );
- Type propertyType = getDataType();
- return propertyType;
+ return getDataType();
}
private void dereferenceCollection(CollectionType collectionType, boolean implicitJoin, boolean indexed, String classAlias, AST parent)
@@ -298,7 +297,7 @@
// select clause is part of a scalar query :/ )
DotNode parentAsDotNode = null;
String property = propertyName;
- boolean joinIsNeeded = false;
+ final boolean joinIsNeeded;
if ( isDotNode( parent ) ) {
parentAsDotNode = ( DotNode ) parent;
@@ -340,13 +339,11 @@
String joinPath = getPath();
if ( impliedJoin && getWalker().isInFrom() ) {
- int impliedJoinType = getWalker().getImpliedJoinType();
- joinType = impliedJoinType;
+ joinType = getWalker().getImpliedJoinType();
}
FromClause currentFromClause = getWalker().getCurrentFromClause();
- FromElement elem = null;
- elem = currentFromClause.findJoinByPath( joinPath );
+ FromElement elem = currentFromClause.findJoinByPath( joinPath );
///////////////////////////////////////////////////////////////////////////////
//
@@ -420,14 +417,42 @@
return impliedJoin;
}
- private boolean isReferenceToPrimaryKey(String propertyName, EntityType propertyType) {
- if ( EntityPersister.ENTITY_ID.equals( propertyName ) ) {
- // the referenced node text is the special 'id'
- return propertyType.isReferenceToPrimaryKey();
+ /**
+ * Is the given property name a reference to the primary key of the associated
+ * entity construed by the given entity type?
+ * <p/>
+ * For example, consider a fragment like order.customer.id
+ * (where order is a from-element alias). Here, we'd have:
+ * propertyName = "id" AND
+ * owningType = ManyToOneType(Customer)
+ * and are being asked to determine whether "customer.id" is a reference
+ * to customer's PK...
+ *
+ * @param propertyName The name of the property to check.
+ * @param owningType The type represeting the entity "owning" the property
+ * @return True if propertyName references the entity's (owningType->associatedEntity)
+ * primary key; false otherwise.
+ */
+ private boolean isReferenceToPrimaryKey(String propertyName, EntityType owningType) {
+ EntityPersister persister = getSessionFactoryHelper()
+ .getFactory()
+ .getEntityPersister( owningType.getAssociatedEntityName() );
+ if ( persister.getEntityMetamodel().hasNonIdentifierPropertyNamedId() ) {
+ // only the identifier property field name can be a reference to the associated entity's PK...
+ return propertyName.equals( persister.getIdentifierPropertyName() ) && owningType.isReferenceToPrimaryKey();
}
else {
- String keyPropertyName = getSessionFactoryHelper().getIdentifierOrUniqueKeyPropertyName( propertyType );
- return keyPropertyName != null && keyPropertyName.equals( propertyName ) && propertyType.isReferenceToPrimaryKey();
+ // here, we have two possibilities:
+ // 1) the property-name matches the explicitly identifier property name
+ // 2) the property-name matches the implicit 'id' property name
+ if ( EntityPersister.ENTITY_ID.equals( propertyName ) ) {
+ // the referenced node text is the special 'id'
+ return owningType.isReferenceToPrimaryKey();
+ }
+ else {
+ String keyPropertyName = getSessionFactoryHelper().getIdentifierOrUniqueKeyPropertyName( owningType );
+ return keyPropertyName != null && keyPropertyName.equals( propertyName ) && owningType.isReferenceToPrimaryKey();
+ }
}
}
Modified: trunk/Hibernate3/src/org/hibernate/hql/ast/tree/FromElement.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/hql/ast/tree/FromElement.java 2006-11-21 17:38:43 UTC (rev 10851)
+++ trunk/Hibernate3/src/org/hibernate/hql/ast/tree/FromElement.java 2006-11-21 17:39:14 UTC (rev 10852)
@@ -5,7 +5,6 @@
import java.util.List;
import org.hibernate.QueryException;
-import org.hibernate.MappingException;
import org.hibernate.engine.JoinSequence;
import org.hibernate.hql.QueryTranslator;
import org.hibernate.hql.CollectionProperties;
@@ -285,11 +284,19 @@
throw new IllegalStateException( "No table alias for node " + this );
}
String[] cols;
+ String propertyName;
+ if ( getEntityPersister() != null && getEntityPersister().getEntityMetamodel() != null
+ && getEntityPersister().getEntityMetamodel().hasNonIdentifierPropertyNamedId() ) {
+ propertyName = getEntityPersister().getIdentifierPropertyName();
+ }
+ else {
+ propertyName = EntityPersister.ENTITY_ID;
+ }
if ( getWalker().getStatementType() == HqlSqlWalker.SELECT ) {
- cols = getPropertyMapping( EntityPersister.ENTITY_ID ).toColumns( table, EntityPersister.ENTITY_ID );
+ cols = getPropertyMapping( propertyName ).toColumns( table, propertyName );
}
else {
- cols = getPropertyMapping( EntityPersister.ENTITY_ID ).toColumns( EntityPersister.ENTITY_ID );
+ cols = getPropertyMapping( propertyName ).toColumns( propertyName );
}
String result = StringHelper.join( ", ", cols );
return cols.length == 1 ? result : "(" + result + ")";
@@ -375,13 +382,6 @@
return origin;
}
- /**
- * Returns the type of a property, given it's name (the last part) and the full path.
- *
- * @param propertyName The last part of the full path to the property.
- * @return The type.
- * @0param propertyPath The full property path.
- */
public Type getPropertyType(String propertyName, String propertyPath) {
return elementType.getPropertyType( propertyName, propertyPath );
}
@@ -422,9 +422,6 @@
return filter;
}
- /**
- * Returns true if the from fragment should be included in the from clause.
- */
public boolean useFromFragment() {
checkInitialized();
// If it's not implied or it is implied and it's a many to many join where the target wasn't found.
@@ -472,10 +469,6 @@
// Do nothing, eplicit from elements are *always* in the projection list.
}
- /**
- * Returns true if this element should be in the projection list.
- *
- */
public boolean inProjectionList() {
return !isImplied() && isFromOrJoinFragment();
}
Modified: trunk/Hibernate3/src/org/hibernate/persister/entity/AbstractEntityPersister.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/persister/entity/AbstractEntityPersister.java 2006-11-21 17:38:43 UTC (rev 10851)
+++ trunk/Hibernate3/src/org/hibernate/persister/entity/AbstractEntityPersister.java 2006-11-21 17:39:14 UTC (rev 10852)
@@ -1508,9 +1508,11 @@
// ALIASES
internalInitSubclassPropertyAliasesMap( null, model.getSubclassPropertyClosureIterator() );
- // aliases for identifier ( alias.id )
- subclassPropertyAliases.put( ENTITY_ID, getIdentifierAliases() );
- subclassPropertyColumnNames.put( ENTITY_ID, getIdentifierColumnNames() );
+ // aliases for identifier ( alias.id ); skip if the entity defines a non-id property named 'id'
+ if ( ! entityMetamodel.hasNonIdentifierPropertyNamedId() ) {
+ subclassPropertyAliases.put( ENTITY_ID, getIdentifierAliases() );
+ subclassPropertyColumnNames.put( ENTITY_ID, getIdentifierColumnNames() );
+ }
// aliases named identifier ( alias.idname )
if ( hasIdentifierProperty() ) {
@@ -1527,23 +1529,26 @@
String[] idColumnNames = getIdentifierColumnNames();
for ( int i = 0; i < idPropertyNames.length; i++ ) {
- subclassPropertyAliases.put(
- ENTITY_ID + "." + idPropertyNames[i],
- new String[] { idAliases[i] }
+ if ( entityMetamodel.hasNonIdentifierPropertyNamedId() ) {
+ subclassPropertyAliases.put(
+ ENTITY_ID + "." + idPropertyNames[i],
+ new String[] { idAliases[i] }
);
- subclassPropertyColumnNames.put(
- ENTITY_ID + "." + getIdentifierPropertyName() + "." + idPropertyNames[i],
- new String[] { idColumnNames[i] }
+ subclassPropertyColumnNames.put(
+ ENTITY_ID + "." + getIdentifierPropertyName() + "." + idPropertyNames[i],
+ new String[] { idColumnNames[i] }
);
- if (hasIdentifierProperty() && !ENTITY_ID.equals( getIdentifierPropertyName() ) ) {
+ }
+// if (hasIdentifierProperty() && !ENTITY_ID.equals( getIdentifierPropertyName() ) ) {
+ if ( hasIdentifierProperty() ) {
subclassPropertyAliases.put(
getIdentifierPropertyName() + "." + idPropertyNames[i],
new String[] { idAliases[i] }
- );
+ );
subclassPropertyColumnNames.put(
getIdentifierPropertyName() + "." + idPropertyNames[i],
new String[] { idColumnNames[i] }
- );
+ );
}
else {
// embedded composite ids ( alias.idname1, alias.idname2 )
@@ -1554,10 +1559,8 @@
}
if ( entityMetamodel.isPolymorphic() ) {
- subclassPropertyAliases.put( ENTITY_CLASS,
- new String[]{getDiscriminatorAlias()} );
- subclassPropertyColumnNames.put( ENTITY_CLASS,
- new String[]{getDiscriminatorColumnName()} );
+ subclassPropertyAliases.put( ENTITY_CLASS, new String[] { getDiscriminatorAlias() } );
+ subclassPropertyColumnNames.put( ENTITY_CLASS, new String[] { getDiscriminatorColumnName() } );
}
}
@@ -1672,7 +1675,9 @@
if ( entityMetamodel.getIdentifierProperty().isEmbedded() ) {
propertyMapping.initPropertyPaths( null, getIdentifierType(), getIdentifierColumnNames(), null, mapping );
}
- propertyMapping.initPropertyPaths( ENTITY_ID, getIdentifierType(), getIdentifierColumnNames(), null, mapping );
+ if ( ! entityMetamodel.hasNonIdentifierPropertyNamedId() ) {
+ propertyMapping.initPropertyPaths( ENTITY_ID, getIdentifierType(), getIdentifierColumnNames(), null, mapping );
+ }
}
private void initDiscriminatorPropertyPath(Mapping mapping) throws MappingException {
@@ -3145,7 +3150,7 @@
return factory;
}
- protected EntityMetamodel getEntityMetamodel() {
+ public EntityMetamodel getEntityMetamodel() {
return entityMetamodel;
}
Modified: trunk/Hibernate3/src/org/hibernate/persister/entity/AbstractPropertyMapping.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/persister/entity/AbstractPropertyMapping.java 2006-11-21 17:38:43 UTC (rev 10851)
+++ trunk/Hibernate3/src/org/hibernate/persister/entity/AbstractPropertyMapping.java 2006-11-21 17:39:14 UTC (rev 10852)
@@ -34,20 +34,16 @@
public Type toType(String propertyName) throws QueryException {
Type type = (Type) typesByPropertyPath.get(propertyName);
- if (type==null) throwPropertyException(propertyName);
+ if ( type == null ) {
+ throw propertyException( propertyName );
+ }
return type;
}
- protected final void throwPropertyException(String propertyName)
- throws QueryException {
- throw new QueryException(
- "could not resolve property: " +
- propertyName +
- " of: " +
- getEntityName()
- );
+ protected final QueryException propertyException(String propertyName) throws QueryException {
+ return new QueryException( "could not resolve property: " + propertyName + " of: " + getEntityName() );
}
-
+
public String[] getColumnNames(String propertyName) {
String[] cols = (String[]) columnsByPropertyPath.get(propertyName);
if (cols==null) {
@@ -56,11 +52,12 @@
return cols;
}
- public String[] toColumns(String alias, String propertyName)
- throws QueryException {
+ public String[] toColumns(String alias, String propertyName) throws QueryException {
//TODO: *two* hashmap lookups here is one too many...
String[] columns = (String[]) columnsByPropertyPath.get(propertyName);
- if (columns==null) throwPropertyException(propertyName);
+ if ( columns == null ) {
+ throw propertyException( propertyName );
+ }
String[] templates = (String[]) formulaTemplatesByPropertyPath.get(propertyName);
String[] result = new String[columns.length];
for ( int i=0; i<columns.length; i++ ) {
@@ -74,10 +71,11 @@
return result;
}
- public String[] toColumns(String propertyName)
- throws QueryException {
+ public String[] toColumns(String propertyName) throws QueryException {
String[] columns = (String[]) columnsByPropertyPath.get(propertyName);
- if (columns==null) throwPropertyException(propertyName);
+ if ( columns == null ) {
+ throw propertyException( propertyName );
+ }
String[] templates = (String[]) formulaTemplatesByPropertyPath.get(propertyName);
String[] result = new String[columns.length];
for ( int i=0; i<columns.length; i++ ) {
@@ -100,28 +98,28 @@
}
/*protected void initPropertyPaths(
- final String path,
- final Type type,
- final String[] columns,
- final String[] formulaTemplates,
+ final String path,
+ final Type type,
+ final String[] columns,
+ final String[] formulaTemplates,
final Mapping factory)
throws MappingException {
//addFormulaPropertyPath(path, type, formulaTemplates);
initPropertyPaths(path, type, columns, formulaTemplates, factory);
}*/
-
+
protected void initPropertyPaths(
- final String path,
- final Type type,
- String[] columns,
- final String[] formulaTemplates,
+ final String path,
+ final Type type,
+ String[] columns,
+ final String[] formulaTemplates,
final Mapping factory)
throws MappingException {
-
+
if ( columns.length!=type.getColumnSpan(factory) ) {
- throw new MappingException(
- "broken column mapping for: " + path +
- " of: " + getEntityName()
+ throw new MappingException(
+ "broken column mapping for: " + path +
+ " of: " + getEntityName()
);
}
@@ -147,12 +145,12 @@
AbstractComponentType actype = (AbstractComponentType) type;
initComponentPropertyPaths( path, actype, columns, formulaTemplates, factory );
if ( actype.isEmbedded() ) {
- initComponentPropertyPaths(
- path==null ? null : StringHelper.qualifier(path),
- actype,
- columns,
- formulaTemplates,
- factory
+ initComponentPropertyPaths(
+ path==null ? null : StringHelper.qualifier(path),
+ actype,
+ columns,
+ formulaTemplates,
+ factory
);
}
}
@@ -162,21 +160,23 @@
}
protected void initIdentifierPropertyPaths(
- final String path,
- final EntityType etype,
- final String[] columns,
- final Mapping factory)
- throws MappingException {
+ final String path,
+ final EntityType etype,
+ final String[] columns,
+ final Mapping factory) throws MappingException {
- Type idtype = etype.getIdentifierOrUniqueKeyType(factory);
+ Type idtype = etype.getIdentifierOrUniqueKeyType( factory );
+ String idPropName = etype.getIdentifierOrUniqueKeyPropertyName(factory);
+ boolean hasNonIdentifierPropertyNamedId = hasNonIdentifierPropertyNamedId( etype, factory );
if ( etype.isReferenceToPrimaryKey() ) {
- String idpath1 = extendPath(path, EntityPersister.ENTITY_ID);
- addPropertyPath(idpath1, idtype, columns, null);
- initPropertyPaths(idpath1, idtype, columns, null, factory);
+ if ( !hasNonIdentifierPropertyNamedId ) {
+ String idpath1 = extendPath(path, EntityPersister.ENTITY_ID);
+ addPropertyPath(idpath1, idtype, columns, null);
+ initPropertyPaths(idpath1, idtype, columns, null, factory);
+ }
}
- String idPropName = etype.getIdentifierOrUniqueKeyPropertyName(factory);
if (idPropName!=null) {
String idpath2 = extendPath(path, idPropName);
addPropertyPath(idpath2, idtype, columns, null);
@@ -184,10 +184,22 @@
}
}
+ private boolean hasNonIdentifierPropertyNamedId(final EntityType entityType, final Mapping factory) {
+ // TODO : would be great to have a Mapping#hasNonIdentifierPropertyNamedId method
+ // I don't believe that Mapping#getReferencedPropertyType accounts for the identifier property; so
+ // if it returns for a property named 'id', then we should have a non-id field named id
+ try {
+ return factory.getReferencedPropertyType( entityType.getAssociatedEntityName(), EntityPersister.ENTITY_ID ) != null;
+ }
+ catch( MappingException e ) {
+ return false;
+ }
+ }
+
protected void initComponentPropertyPaths(
- final String path,
- final AbstractComponentType type,
- final String[] columns,
+ final String path,
+ final AbstractComponentType type,
+ final String[] columns,
String[] formulaTemplates, final Mapping factory)
throws MappingException {
@@ -199,7 +211,7 @@
try {
int length = types[i].getColumnSpan(factory);
String[] columnSlice = ArrayHelper.slice(columns, begin, length);
- String[] formulaSlice = formulaTemplates==null ?
+ String[] formulaSlice = formulaTemplates==null ?
null : ArrayHelper.slice(formulaTemplates, begin, length);
initPropertyPaths(subpath, types[i], columnSlice, formulaSlice, factory);
begin+=length;
Modified: trunk/Hibernate3/src/org/hibernate/persister/entity/EntityPersister.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/persister/entity/EntityPersister.java 2006-11-21 17:38:43 UTC (rev 10851)
+++ trunk/Hibernate3/src/org/hibernate/persister/entity/EntityPersister.java 2006-11-21 17:39:14 UTC (rev 10852)
@@ -8,6 +8,7 @@
import org.hibernate.LockMode;
import org.hibernate.MappingException;
import org.hibernate.EntityMode;
+import org.hibernate.tuple.entity.EntityMetamodel;
import org.hibernate.cache.CacheConcurrencyStrategy;
import org.hibernate.cache.OptimisticCacheSource;
import org.hibernate.cache.entry.CacheEntryStructure;
@@ -74,6 +75,13 @@
public String getEntityName();
/**
+ * Retrieve the underlying entity metamodel instance...
+ *
+ *@return The metamodel
+ */
+ public EntityMetamodel getEntityMetamodel();
+
+ /**
* Determine whether the given name represents a subclass entity
* (or this entity itself) of the entity mapped by this persister.
*
Modified: trunk/Hibernate3/src/org/hibernate/tuple/entity/EntityMetamodel.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/tuple/entity/EntityMetamodel.java 2006-11-21 17:38:43 UTC (rev 10851)
+++ trunk/Hibernate3/src/org/hibernate/tuple/entity/EntityMetamodel.java 2006-11-21 17:39:14 UTC (rev 10852)
@@ -40,7 +40,7 @@
* @author Steve Ebersole
*/
public class EntityMetamodel implements Serializable {
-
+
private static final Log log = LogFactory.getLog(EntityMetamodel.class);
private static final int NO_VERSION_INDX = -66;
@@ -73,12 +73,13 @@
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
private final Map propertyIndexes = new HashMap();
private final boolean hasCollections;
- private final boolean hasMutableProperties;
+ private final boolean hasMutableProperties;
private final boolean hasLazyProperties;
+ private final boolean hasNonIdentifierPropertyNamedId;
private final int[] naturalIdPropertyNumbers;
- private boolean lazy; //not final, proxy factory creation may fail
+ private boolean lazy; //not final because proxy factory creation can fail
private final boolean hasCascades;
private final boolean mutable;
private final boolean isAbstract;
@@ -95,7 +96,7 @@
private final Set subclassEntityNames = new HashSet();
private final EntityEntityModeToTuplizerMapping tuplizerMapping;
-
+
public EntityTuplizer getTuplizer(EntityMode entityMode) {
return (EntityTuplizer) tuplizerMapping.getTuplizer( entityMode );
}
@@ -103,7 +104,7 @@
public EntityTuplizer getTuplizerOrNull(EntityMode entityMode) {
return ( EntityTuplizer ) tuplizerMapping.getTuplizerOrNull( entityMode );
}
-
+
public EntityMode guessEntityMode(Object object) {
return tuplizerMapping.guessEntityMode( object );
}
@@ -151,7 +152,8 @@
boolean foundCascade = false;
boolean foundCollection = false;
boolean foundMutable = false;
-
+ boolean foundNonIdentifierPropertyNamedId = false;
+
while ( iter.hasNext() ) {
Property prop = ( Property ) iter.next();
@@ -162,11 +164,15 @@
else {
properties[i] = PropertyFactory.buildStandardProperty( prop, lazyAvailable );
}
-
+
if ( prop.isNaturalIdentifier() ) {
naturalIdNumbers.add( new Integer(i) );
}
+ if ( "id".equals( prop.getName() ) ) {
+ foundNonIdentifierPropertyNamedId = true;
+ }
+
// temporary ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
boolean lazy = prop.isLazy() && lazyAvailable;
if ( lazy ) hasLazy = true;
@@ -181,7 +187,7 @@
propertyUpdateGeneration[i] = properties[i].isUpdateGenerated();
propertyVersionability[i] = properties[i].isVersionable();
nonlazyPropertyUpdateability[i] = properties[i].isUpdateable() && !lazy;
- propertyCheckability[i] = propertyUpdateability[i] ||
+ propertyCheckability[i] = propertyUpdateability[i] ||
( propertyTypes[i].isAssociationType() && ( (AssociationType) propertyTypes[i] ).isAlwaysDirtyChecked() );
cascadeStyles[i] = properties[i].getCascadeStyle();
@@ -198,7 +204,7 @@
if ( indicatesCollection( properties[i].getType() ) ) {
foundCollection = true;
}
-
+
if ( propertyTypes[i].isMutable() && propertyCheckability[i] ) {
foundMutable = true;
}
@@ -206,7 +212,7 @@
mapPropertyToIndex(prop, i);
i++;
}
-
+
if (naturalIdNumbers.size()==0) {
naturalIdPropertyNumbers = null;
}
@@ -215,9 +221,12 @@
}
hasCascades = foundCascade;
+ hasNonIdentifierPropertyNamedId = foundNonIdentifierPropertyNamedId;
versionPropertyIndex = tempVersionProperty;
hasLazyProperties = hasLazy;
- if (hasLazyProperties) log.info("lazy property fetching available for: " + name);
+ if ( hasLazyProperties ) {
+ log.info( "lazy property fetching available for: " + name );
+ }
lazy = persistentClass.isLazy() && (
// TODO: this disables laziness even in non-pojo entity modes:
@@ -275,22 +284,22 @@
Iterator iter = ( (Component) prop.getValue() ).getPropertyIterator();
while ( iter.hasNext() ) {
Property subprop = (Property) iter.next();
- propertyIndexes.put(
- prop.getName() + '.' + subprop.getName(),
- new Integer(i)
+ propertyIndexes.put(
+ prop.getName() + '.' + subprop.getName(),
+ new Integer(i)
);
}
}
}
-
+
public int[] getNaturalIdentifierProperties() {
return naturalIdPropertyNumbers;
}
-
+
public boolean hasNaturalIdentifier() {
return naturalIdPropertyNumbers!=null;
}
-
+
public Set getSubclassEntityNames() {
return subclassEntityNames;
}
@@ -358,7 +367,7 @@
}
return index.intValue();
}
-
+
public Integer getPropertyIndexOrNull(String propertyName) {
return (Integer) propertyIndexes.get( propertyName );
}
@@ -366,11 +375,15 @@
public boolean hasCollections() {
return hasCollections;
}
-
+
public boolean hasMutableProperties() {
return hasMutableProperties;
}
+ public boolean hasNonIdentifierPropertyNamedId() {
+ return hasNonIdentifierPropertyNamedId;
+ }
+
public boolean hasLazyProperties() {
return hasLazyProperties;
}
@@ -434,11 +447,11 @@
public boolean isAbstract() {
return isAbstract;
}
-
+
public String toString() {
return "EntityMetamodel(" + name + ':' + ArrayHelper.toString(properties) + ')';
}
-
+
// temporary ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public String[] getPropertyNames() {
return propertyNames;
Added: trunk/Hibernate3/test/org/hibernate/test/idprops/IdentifierPropertyReferencesTest.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/idprops/IdentifierPropertyReferencesTest.java 2006-11-21 17:38:43 UTC (rev 10851)
+++ trunk/Hibernate3/test/org/hibernate/test/idprops/IdentifierPropertyReferencesTest.java 2006-11-21 17:39:14 UTC (rev 10852)
@@ -0,0 +1,187 @@
+package org.hibernate.test.idprops;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.test.TestCase;
+import org.hibernate.Session;
+import org.hibernate.Query;
+import org.hibernate.Criteria;
+import org.hibernate.criterion.Projections;
+import org.hibernate.criterion.Restrictions;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class IdentifierPropertyReferencesTest extends TestCase {
+ public IdentifierPropertyReferencesTest(String name) {
+ super( name );
+ }
+
+ protected String[] getMappings() {
+ return new String[] { "idprops/Mapping.hbm.xml" };
+ }
+
+ public static Test suite() {
+ return new TestSuite( IdentifierPropertyReferencesTest.class );
+ }
+
+ public void testHqlIdPropertyReferences() {
+ Session s = openSession();
+ s.beginTransaction();
+ Person p = new Person( new Long(1), "steve", 123 );
+ s.save( p );
+ Order o = new Order( new Long(1), p );
+ LineItem l = new LineItem( o, "my-product", 2 );
+ l.setId( "456" );
+ s.save( o );
+ s.getTransaction().commit();
+ s.close();
+
+ s = openSession();
+ s.beginTransaction();
+
+ long count = extractCount( s, "select count(*) from Person p where p.id = 123" );
+ assertEquals( "Person by id prop (non-identifier)", 1, count );
+ count = extractCount( s, "select count(*) from Person p where p.pk = 1" );
+ assertEquals( "Person by pk prop (identifier)", 1, count );
+
+ count = extractCount( s, "select count(*) from Order o where o.id = 1" );
+ assertEquals( "Order by number prop (named identifier)", 1, count );
+ count = extractCount( s, "select count(*) from Order o where o.number = 1" );
+ assertEquals( "Order by id prop (virtual identifier)", 1, count );
+
+ count = extractCount( s, "select count(*) from LineItem l where l.id = '456'" );
+ assertEquals( "LineItem by id prop (non-identifier", 1, count );
+
+ if ( getDialect().supportsRowValueConstructorSyntax() ) {
+ Query q = s.createQuery( "select count(*) from LineItem l where l.pk = (:order, :product)" )
+ .setEntity( "order", o )
+ .setString( "product", "my-product" );
+ count = extractCount( q );
+ assertEquals( "LineItem by pk prop (named composite identifier", 1, count );
+ }
+
+ count = extractCount( s, "select count(*) from Order o where o.orderee.id = 1" );
+ assertEquals( 0, count );
+ count = extractCount( s, "select count(*) from Order o where o.orderee.pk = 1" );
+ assertEquals( 1, count );
+ count = extractCount( s, "select count(*) from Order o where o.orderee.id = 123" );
+ assertEquals( 1, count );
+
+ count = extractCount( s, "select count(*) from LineItem l where l.pk.order.id = 1" );
+ assertEquals( 1, count );
+ count = extractCount( s, "select count(*) from LineItem l where l.pk.order.number = 1" );
+ assertEquals( 1, count );
+ count = extractCount( s, "select count(*) from LineItem l where l.pk.order.orderee.pk = 1" );
+ assertEquals( 1, count );
+
+ s.delete( o );
+ s.delete( p );
+ s.getTransaction().commit();
+ s.close();
+ }
+
+ public void testCriteriaIdPropertyReferences() {
+ Session s = openSession();
+ s.beginTransaction();
+ Person p = new Person( new Long(1), "steve", 123 );
+ s.save( p );
+ Order o = new Order( new Long(1), p );
+ LineItem l = new LineItem( o, "my-product", 2 );
+ l.setId( "456" );
+ s.save( o );
+ s.getTransaction().commit();
+ s.close();
+
+ s = openSession();
+ s.beginTransaction();
+
+ Criteria crit = s.createCriteria( Person.class );
+ crit.setProjection( Projections.rowCount() );
+ crit.add( Restrictions.eq( "id", new Integer(123) ) );
+ long count = extractCount( crit );
+ assertEquals( "Person by id prop (non-identifier)", 1, count );
+
+ crit = s.createCriteria( Person.class );
+ crit.setProjection( Projections.rowCount() );
+ crit.add( Restrictions.eq( "pk", new Long(1) ) );
+ count = extractCount( crit );
+ assertEquals( "Person by pk prop (identifier)", 1, count );
+
+ crit = s.createCriteria( Order.class );
+ crit.setProjection( Projections.rowCount() );
+ crit.add( Restrictions.eq( "number", new Long(1) ) );
+ count = extractCount( crit );
+ assertEquals( "Order by number prop (named identifier)", 1, count );
+
+ crit = s.createCriteria( Order.class );
+ crit.setProjection( Projections.rowCount() );
+ crit.add( Restrictions.eq( "id", new Long(1) ) );
+ count = extractCount( crit );
+ assertEquals( "Order by id prop (virtual identifier)", 1, count );
+
+ crit = s.createCriteria( LineItem.class );
+ crit.setProjection( Projections.rowCount() );
+ crit.add( Restrictions.eq( "id", "456" ) );
+ count = extractCount( crit );
+ assertEquals( "LineItem by id prop (non-identifier", 1, count );
+
+ if ( getDialect().supportsRowValueConstructorSyntax() ) {
+ crit = s.createCriteria( LineItem.class );
+ crit.setProjection( Projections.rowCount() );
+ crit.add( Restrictions.eq( "pk", new LineItemPK( o, "my-product" ) ) );
+ count = extractCount( crit );
+ assertEquals( "LineItem by pk prop (named composite identifier)", 1, count );
+ }
+
+ crit = s.createCriteria( Order.class );
+ crit.setProjection( Projections.rowCount() );
+ crit.createAlias( "orderee", "p" ).add( Restrictions.eq( "p.id", new Integer(1) ) );
+ count = extractCount( crit );
+ assertEquals( 0, count );
+
+ crit = s.createCriteria( Order.class );
+ crit.setProjection( Projections.rowCount() );
+ crit.createAlias( "orderee", "p" ).add( Restrictions.eq( "p.pk", new Long(1) ) );
+ count = extractCount( crit );
+ assertEquals( 1, count );
+
+ crit = s.createCriteria( Order.class );
+ crit.setProjection( Projections.rowCount() );
+ crit.createAlias( "orderee", "p" ).add( Restrictions.eq( "p.id", new Integer(123) ) );
+ count = extractCount( crit );
+ assertEquals( 1, count );
+
+ crit = s.createCriteria( LineItem.class );
+ crit.setProjection( Projections.rowCount() );
+ crit.add( Restrictions.eq( "pk.order.id", new Long(1) ) );
+ count = extractCount( crit );
+ assertEquals( 1, count );
+
+ crit = s.createCriteria( LineItem.class );
+ crit.setProjection( Projections.rowCount() );
+ crit.add( Restrictions.eq( "pk.order.number", new Long(1) ) );
+ count = extractCount( crit );
+ assertEquals( 1, count );
+
+ s.delete( o );
+ s.delete( p );
+ s.getTransaction().commit();
+ s.close();
+ }
+
+ private long extractCount(Session s, String hql) {
+ return extractCount( s.createQuery( hql ) );
+ }
+
+ private long extractCount(Query query) {
+ return ( ( Long ) query.list().get( 0 ) ).longValue();
+ }
+
+ private long extractCount(Criteria crit) {
+ return ( ( Integer ) crit.list().get( 0 ) ).intValue();
+ }
+}
Added: trunk/Hibernate3/test/org/hibernate/test/idprops/LineItem.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/idprops/LineItem.java 2006-11-21 17:38:43 UTC (rev 10851)
+++ trunk/Hibernate3/test/org/hibernate/test/idprops/LineItem.java 2006-11-21 17:39:14 UTC (rev 10852)
@@ -0,0 +1,49 @@
+package org.hibernate.test.idprops;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class LineItem {
+ private LineItemPK pk;
+ private int quantity;
+ private String id;
+
+ public LineItem() {
+ }
+
+ public LineItem(LineItemPK pk, int quantity) {
+ this.pk = pk;
+ this.quantity = quantity;
+ this.pk.getOrder().getLineItems().add( this );
+ }
+
+ public LineItem(Order order, String productCode, int quantity) {
+ this( new LineItemPK( order, productCode ), quantity );
+ }
+
+ public LineItemPK getPk() {
+ return pk;
+ }
+
+ public void setPk(LineItemPK pk) {
+ this.pk = pk;
+ }
+
+ public int getQuantity() {
+ return quantity;
+ }
+
+ public void setQuantity(int quantity) {
+ this.quantity = quantity;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+}
Added: trunk/Hibernate3/test/org/hibernate/test/idprops/LineItemPK.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/idprops/LineItemPK.java 2006-11-21 17:38:43 UTC (rev 10851)
+++ trunk/Hibernate3/test/org/hibernate/test/idprops/LineItemPK.java 2006-11-21 17:39:14 UTC (rev 10852)
@@ -0,0 +1,64 @@
+package org.hibernate.test.idprops;
+
+import java.io.Serializable;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class LineItemPK implements Serializable {
+ private Order order;
+ private String productCode;
+
+ public LineItemPK() {
+ }
+
+ public LineItemPK(Order order, String productCode) {
+ this.order = order;
+ this.productCode = productCode;
+ }
+
+ public Order getOrder() {
+ return order;
+ }
+
+ public void setOrder(Order order) {
+ this.order = order;
+ }
+
+ public String getProductCode() {
+ return productCode;
+ }
+
+ public void setProductCode(String productCode) {
+ this.productCode = productCode;
+ }
+
+ public boolean equals(Object o) {
+ if ( this == o ) {
+ return true;
+ }
+ if ( o == null || getClass() != o.getClass() ) {
+ return false;
+ }
+
+ LineItemPK that = ( LineItemPK ) o;
+
+ if ( !order.equals( that.order ) ) {
+ return false;
+ }
+ if ( !productCode.equals( that.productCode ) ) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public int hashCode() {
+ int result;
+ result = order.hashCode();
+ result = 31 * result + productCode.hashCode();
+ return result;
+ }
+}
Added: trunk/Hibernate3/test/org/hibernate/test/idprops/Mapping.hbm.xml
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/idprops/Mapping.hbm.xml 2006-11-21 17:38:43 UTC (rev 10851)
+++ trunk/Hibernate3/test/org/hibernate/test/idprops/Mapping.hbm.xml 2006-11-21 17:39:14 UTC (rev 10852)
@@ -0,0 +1,48 @@
+<?xml version="1.0"?>
+
+<!DOCTYPE hibernate-mapping SYSTEM "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
+
+<hibernate-mapping package="org.hibernate.test.idprops">
+
+ <!--
+ Person has an identitifer property named something other than 'id';
+ additionally, it has a non-identitifer property named 'id'
+ -->
+ <class name="Person" table="T_ID_PERSON">
+ <id name="pk" column="PK" type="long">
+ <generator class="assigned"/>
+ </id>
+ <property name="name" column="NAME" type="string"/>
+ <property name="id" column="ID_NON_ID" type="int" />
+ </class>
+
+ <!--
+ Order has an identitifer property named something other than 'id';
+ it has no non-identitifer property named 'id'
+ -->
+ <class name="Order" table="T_ID_ORDER">
+ <id name="number" column="PK" type="long">
+ <generator class="assigned"/>
+ </id>
+ <property name="placed" column="ORDR_DT" type="timestamp"/>
+ <many-to-one name="orderee" class="Person" column="ORDEREE"/>
+ <set name="lineItems" cascade="all-delete-orphan" lazy="true" inverse="true">
+ <key column="ORDR_ID"/>
+ <one-to-many class="LineItem"/>
+ </set>
+ </class>
+
+ <!--
+ LineItem has a composite identitifer property named something other than 'id';
+ additionally, it has a non-identitifer property named 'id'
+ -->
+ <class name="LineItem" table="T_ID_LINE_ITEM">
+ <composite-id class="LineItemPK" name="pk">
+ <key-many-to-one name="order" class="Order" column="ORDR_ID" />
+ <key-property name="productCode" column="PROD_CODE" type="string"/>
+ </composite-id>
+ <property name="quantity" column="QTY" type="int"/>
+ <property name="id" column="ID_NON_ID2" type="string"/>
+ </class>
+
+</hibernate-mapping>
\ No newline at end of file
Added: trunk/Hibernate3/test/org/hibernate/test/idprops/Order.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/idprops/Order.java 2006-11-21 17:38:43 UTC (rev 10851)
+++ trunk/Hibernate3/test/org/hibernate/test/idprops/Order.java 2006-11-21 17:39:14 UTC (rev 10852)
@@ -0,0 +1,60 @@
+package org.hibernate.test.idprops;
+
+import java.util.Date;
+import java.util.Set;
+import java.util.HashSet;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class Order {
+ private Long number;
+ private Date placed;
+ private Person orderee;
+
+ private Set lineItems = new HashSet();
+
+ public Order() {
+ }
+
+ public Order(Long number, Person orderee) {
+ this.number = number;
+ this.orderee = orderee;
+ this.placed = new Date();
+ }
+
+ public Long getNumber() {
+ return number;
+ }
+
+ public void setNumber(Long number) {
+ this.number = number;
+ }
+
+ public Date getPlaced() {
+ return placed;
+ }
+
+ public void setPlaced(Date placed) {
+ this.placed = placed;
+ }
+
+ public Person getOrderee() {
+ return orderee;
+ }
+
+ public void setOrderee(Person orderee) {
+ this.orderee = orderee;
+ }
+
+
+ public Set getLineItems() {
+ return lineItems;
+ }
+
+ public void setLineItems(Set lineItems) {
+ this.lineItems = lineItems;
+ }
+}
Added: trunk/Hibernate3/test/org/hibernate/test/idprops/Person.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/idprops/Person.java 2006-11-21 17:38:43 UTC (rev 10851)
+++ trunk/Hibernate3/test/org/hibernate/test/idprops/Person.java 2006-11-21 17:39:14 UTC (rev 10852)
@@ -0,0 +1,45 @@
+package org.hibernate.test.idprops;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class Person {
+ private Long pk;
+ private String name;
+ private int id;
+
+ public Person() {
+ }
+
+ public Person(Long pk, String name, int id) {
+ this.pk = pk;
+ this.name = name;
+ this.id = id;
+ }
+
+ public Long getPk() {
+ return pk;
+ }
+
+ public void setPk(Long pk) {
+ this.pk = pk;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+}
Modified: trunk/Hibernate3/test/org/hibernate/test/legacy/CustomPersister.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/legacy/CustomPersister.java 2006-11-21 17:38:43 UTC (rev 10851)
+++ trunk/Hibernate3/test/org/hibernate/test/legacy/CustomPersister.java 2006-11-21 17:39:14 UTC (rev 10852)
@@ -11,6 +11,7 @@
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.MappingException;
+import org.hibernate.tuple.entity.EntityMetamodel;
import org.hibernate.cache.CacheConcurrencyStrategy;
import org.hibernate.cache.entry.CacheEntryStructure;
import org.hibernate.cache.entry.UnstructuredCacheEntry;
@@ -76,7 +77,7 @@
public String getEntityName() {
return Custom.class.getName();
}
-
+
public boolean isSubclassEntityName(String entityName) {
return Custom.class.getName().equals(entityName);
}
@@ -616,4 +617,9 @@
public Comparator getVersionComparator() {
return null;
}
+
+ public EntityMetamodel getEntityMetamodel() {
+ return null;
+ }
+
}
18 years, 1 month
Hibernate SVN: r10851 - in branches/Branch_3_2/Hibernate3: doc/reference/en/modules src/org/hibernate/hql/ast/tree src/org/hibernate/persister/entity src/org/hibernate/tuple/entity test/org/hibernate/test test/org/hibernate/test/idprops test/org/hibernate/test/legacy
by hibernate-commits@lists.jboss.org
Author: steve.ebersole(a)jboss.com
Date: 2006-11-21 12:38:43 -0500 (Tue, 21 Nov 2006)
New Revision: 10851
Added:
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idprops/
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idprops/IdentifierPropertyReferencesTest.java
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idprops/LineItem.java
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idprops/LineItemPK.java
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idprops/Mapping.hbm.xml
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idprops/Order.java
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idprops/Person.java
Modified:
branches/Branch_3_2/Hibernate3/doc/reference/en/modules/query_hql.xml
branches/Branch_3_2/Hibernate3/src/org/hibernate/hql/ast/tree/DotNode.java
branches/Branch_3_2/Hibernate3/src/org/hibernate/hql/ast/tree/FromElement.java
branches/Branch_3_2/Hibernate3/src/org/hibernate/persister/entity/AbstractEntityPersister.java
branches/Branch_3_2/Hibernate3/src/org/hibernate/persister/entity/AbstractPropertyMapping.java
branches/Branch_3_2/Hibernate3/src/org/hibernate/persister/entity/EntityPersister.java
branches/Branch_3_2/Hibernate3/src/org/hibernate/tuple/entity/EntityMetamodel.java
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/legacy/CustomPersister.java
Log:
HHH-1851 : relax special 'id' property handling
Modified: branches/Branch_3_2/Hibernate3/doc/reference/en/modules/query_hql.xml
===================================================================
--- branches/Branch_3_2/Hibernate3/doc/reference/en/modules/query_hql.xml 2006-11-21 16:33:52 UTC (rev 10850)
+++ branches/Branch_3_2/Hibernate3/doc/reference/en/modules/query_hql.xml 2006-11-21 17:38:43 UTC (rev 10851)
@@ -1,4 +1,4 @@
-<chapter id="queryhql">
+<chapter id="queryhql" revision="1">
<title>HQL: The Hibernate Query Language</title>
<para>
@@ -210,6 +210,42 @@
<programlisting><![CDATA[from Cat as cat where cat.mate.name like '%s%']]></programlisting>
</sect1>
+ <sect1 id="queryhql-identifier-property">
+ <title>Refering to identifier property</title>
+
+ <para>
+ There are, generally speaking, 2 ways to refer to an entity's identifier property:
+ </para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ The special property (lowercase) <literal>id</literal> may be used to reference the identifier
+ property of an entity <emphasis>provided that entity does not define a non-identifier property
+ named id</emphasis>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ If the entity defines a named identifier property, you may use that property name.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ References to composite identifier properties follow the same naming rules. If the
+ entity has a non-identifier property named id, the composite identifier property can only
+ be referenced by its defined named; otherwise, the special <literal>id</literal> property
+ can be used to rerference the identifier property.
+ </para>
+
+ <para>
+ Note: this has changed significantly starting in version 3.2.2. In previous versions,
+ <literal>id</literal> <emphasis>always</emphasis> referred to the identifier property no
+ matter what its actual name. A ramification of that decision was that non-identifier
+ properties named <literal>id</literal> could never be referenced in Hibernate queries.
+ </para>
+ </sect1>
+
<sect1 id="queryhql-select">
<title>The select clause</title>
@@ -389,7 +425,7 @@
</sect1>
- <sect1 id="queryhql-where">
+ <sect1 id="queryhql-where" revision="1">
<title>The where clause</title>
<para>
@@ -448,8 +484,9 @@
where cat.mate = mate]]></programlisting>
<para>
- The special property (lowercase) <literal>id</literal> may be used to reference the
- unique identifier of an object. (You may also use its property name.)
+ The special property (lowercase) <literal>id</literal> may be used to reference the
+ unique identifier of an object. See <xref linkend="queryhql-identifier-property"/>
+ for more information.
</para>
<programlisting><![CDATA[from Cat as cat where cat.id = 123
@@ -463,7 +500,8 @@
<para>
Properties of composite identifiers may also be used. Suppose <literal>Person</literal>
has a composite identifier consisting of <literal>country</literal> and
- <literal>medicareNumber</literal>.
+ <literal>medicareNumber</literal>. Again, see <xref linkend="queryhql-identifier-property"/>
+ for more information regarding referencing identifier properties.
</para>
<programlisting><![CDATA[from bank.Person person
@@ -477,7 +515,7 @@
<para>
Once again, the second query requires no table join.
</para>
-
+
<para>
Likewise, the special property <literal>class</literal> accesses the discriminator value
of an instance in the case of polymorphic persistence. A Java class name embedded in the
@@ -485,17 +523,12 @@
</para>
<programlisting><![CDATA[from Cat cat where cat.class = DomesticCat]]></programlisting>
-
+
<para>
- You may also specify properties of components or composite user types (and of components
- of components, etc). Never try to use a path-expression that ends in a property of component
- type (as opposed to a property of a component). For example, if <literal>store.owner</literal>
- is an entity with a component <literal>address</literal>
+ You may also use components or composite user types, or properties of said
+ component types. See <xref linkend="queryhql-coomponents"/> for more details.
</para>
- <programlisting><![CDATA[store.owner.address.city // okay
-store.owner.address // error!]]></programlisting>
-
<para>
An "any" type has the special properties <literal>id</literal> and <literal>class</literal>,
allowing us to express a join in the following way (where <literal>AuditLog.item</literal>
@@ -869,7 +902,7 @@
</sect1>
- <sect1 id="queryhql-subqueries" revision="2">
+ <sect1 id="queryhql-subqueries" revision="3">
<title>Subqueries</title>
<para>
@@ -906,33 +939,10 @@
</para>
<para>
- For subqueries with more than one expression in the select list, you can use a tuple constructor:
+ Note that subqueries can also utilize <literal>row value constructor</literal> syntax. See
+ <xref linkend="queryhql-tuple"/> for more details.
</para>
- <programlisting><![CDATA[from Cat as cat
-where not ( cat.name, cat.color ) in (
- select cat.name, cat.color from DomesticCat cat
-)]]></programlisting>
-
- <para>
- Note that on some databases (but not Oracle or HSQL), you can use tuple constructors in other
- contexts, for example when querying components or composite user types:
- </para>
-
- <programlisting><![CDATA[from Person where name = ('Gavin', 'A', 'King')]]></programlisting>
-
- <para>
- Which is equivalent to the more verbose:
- </para>
-
- <programlisting><![CDATA[from Person where name.first = 'Gavin' and name.initial = 'A' and name.last = 'King')]]></programlisting>
-
- <para>
- There are two good reasons you might not want to do this kind of thing: first, it is not
- completely portable between database platforms; second, the query is now dependent upon
- the ordering of properties in the mapping document.
- </para>
-
</sect1>
<sect1 id="queryhql-examples">
@@ -1147,5 +1157,78 @@
</sect1>
+ <sect1 id="queryhql-components">
+ <title>Components</title>
+
+ <para>
+ Components might be used in just about every way that simple value types can be used in HQL
+ queries. They can appear in the <literal>select</literal> clause:
+ </para>
+
+ <programlisting><![CDATA[select p.name from from Person p]]></programlisting>
+ <programlisting><![CDATA[select p.name.first from from Person p]]></programlisting>
+
+ <para>
+ where the Person's name property is a component. Components can also be used
+ in the <literal>where</literal> clause:
+ </para>
+
+ <programlisting><![CDATA[from from Person p where p.name = :name]]></programlisting>
+ <programlisting><![CDATA[from from Person p where p.name.first = :firstName]]></programlisting>
+
+ <para>
+ Components can also be used in the <literal>order by</literal> clause:
+ </para>
+
+ <programlisting><![CDATA[from from Person p order by p.name]]></programlisting>
+ <programlisting><![CDATA[from from Person p order by p.name.first]]></programlisting>
+
+ <para>
+ Another common use of components is in <xref linkend="queryhql-tuple">row value constructors</xref>.
+ </para>
+ </sect1>
+
+ <sect1 id="queryhql-tuple">
+ <title>Row value constructor syntax</title>
+
+ <para>
+ HQL supports the use of ANSI SQL <literal>row value constructor</literal> syntax (sometimes
+ called <literal>tuple</literal> syntax), even though the underlying database may not support
+ that notion. Here we are generally referring to multi-valued comparisons, typically associated
+ with components. Consider an entity Person which defines a name component:
+ </para>
+
+ <programlisting><![CDATA[from Person p where p.name.first='John' and p.name.last='Jingleheimer-Schmidt']]></programlisting>
+
+ <para>
+ That's valid syntax, although a little verbose. It be nice to make this a bit more concise and use
+ <literal>row value constructor</literal> syntax:
+ </para>
+
+ <programlisting><![CDATA[from Person p where p.name=('John', 'Jingleheimer-Schmidt')]]></programlisting>
+
+ <para>
+ It can also be useful to specify this in the <literal>select</literal> clause:
+ </para>
+
+ <programlisting><![CDATA[select p.name from from Person p]]></programlisting>
+
+ <para>
+ Another time using <literal>row value constructor</literal> syntax can be beneficial
+ is when using subqueries needing to compare against multiple values:
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat
+where not ( cat.name, cat.color ) in (
+ select cat.name, cat.color from DomesticCat cat
+)]]></programlisting>
+
+ <para>
+ One thing to consider when deciding if you want to use this syntax is that the query will
+ be dependent upon the ordering of the component sub-properties in the metadata.
+ </para>
+
+ </sect1>
+
</chapter>
Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/hql/ast/tree/DotNode.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/hql/ast/tree/DotNode.java 2006-11-21 16:33:52 UTC (rev 10850)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/hql/ast/tree/DotNode.java 2006-11-21 17:38:43 UTC (rev 10851)
@@ -81,9 +81,9 @@
private FromElement impliedJoin;
/**
- * Sets the join type for the '.' node (JoinFragment.XXX).
+ * Sets the join type for this '.' node structure.
*
- * @param joinType
+ * @param joinType The type of join to use.
* @see JoinFragment
*/
public void setJoinType(int joinType) {
@@ -220,8 +220,7 @@
private Type prepareLhs() throws SemanticException {
FromReferenceNode lhs = getLhs();
lhs.prepareForDot( propertyName );
- Type propertyType = getDataType();
- return propertyType;
+ return getDataType();
}
private void dereferenceCollection(CollectionType collectionType, boolean implicitJoin, boolean indexed, String classAlias, AST parent)
@@ -298,7 +297,7 @@
// select clause is part of a scalar query :/ )
DotNode parentAsDotNode = null;
String property = propertyName;
- boolean joinIsNeeded = false;
+ final boolean joinIsNeeded;
if ( isDotNode( parent ) ) {
parentAsDotNode = ( DotNode ) parent;
@@ -340,13 +339,11 @@
String joinPath = getPath();
if ( impliedJoin && getWalker().isInFrom() ) {
- int impliedJoinType = getWalker().getImpliedJoinType();
- joinType = impliedJoinType;
+ joinType = getWalker().getImpliedJoinType();
}
FromClause currentFromClause = getWalker().getCurrentFromClause();
- FromElement elem = null;
- elem = currentFromClause.findJoinByPath( joinPath );
+ FromElement elem = currentFromClause.findJoinByPath( joinPath );
///////////////////////////////////////////////////////////////////////////////
//
@@ -420,14 +417,42 @@
return impliedJoin;
}
- private boolean isReferenceToPrimaryKey(String propertyName, EntityType propertyType) {
- if ( EntityPersister.ENTITY_ID.equals( propertyName ) ) {
- // the referenced node text is the special 'id'
- return propertyType.isReferenceToPrimaryKey();
+ /**
+ * Is the given property name a reference to the primary key of the associated
+ * entity construed by the given entity type?
+ * <p/>
+ * For example, consider a fragment like order.customer.id
+ * (where order is a from-element alias). Here, we'd have:
+ * propertyName = "id" AND
+ * owningType = ManyToOneType(Customer)
+ * and are being asked to determine whether "customer.id" is a reference
+ * to customer's PK...
+ *
+ * @param propertyName The name of the property to check.
+ * @param owningType The type represeting the entity "owning" the property
+ * @return True if propertyName references the entity's (owningType->associatedEntity)
+ * primary key; false otherwise.
+ */
+ private boolean isReferenceToPrimaryKey(String propertyName, EntityType owningType) {
+ EntityPersister persister = getSessionFactoryHelper()
+ .getFactory()
+ .getEntityPersister( owningType.getAssociatedEntityName() );
+ if ( persister.getEntityMetamodel().hasNonIdentifierPropertyNamedId() ) {
+ // only the identifier property field name can be a reference to the associated entity's PK...
+ return propertyName.equals( persister.getIdentifierPropertyName() ) && owningType.isReferenceToPrimaryKey();
}
else {
- String keyPropertyName = getSessionFactoryHelper().getIdentifierOrUniqueKeyPropertyName( propertyType );
- return keyPropertyName != null && keyPropertyName.equals( propertyName ) && propertyType.isReferenceToPrimaryKey();
+ // here, we have two possibilities:
+ // 1) the property-name matches the explicitly identifier property name
+ // 2) the property-name matches the implicit 'id' property name
+ if ( EntityPersister.ENTITY_ID.equals( propertyName ) ) {
+ // the referenced node text is the special 'id'
+ return owningType.isReferenceToPrimaryKey();
+ }
+ else {
+ String keyPropertyName = getSessionFactoryHelper().getIdentifierOrUniqueKeyPropertyName( owningType );
+ return keyPropertyName != null && keyPropertyName.equals( propertyName ) && owningType.isReferenceToPrimaryKey();
+ }
}
}
Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/hql/ast/tree/FromElement.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/hql/ast/tree/FromElement.java 2006-11-21 16:33:52 UTC (rev 10850)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/hql/ast/tree/FromElement.java 2006-11-21 17:38:43 UTC (rev 10851)
@@ -5,7 +5,6 @@
import java.util.List;
import org.hibernate.QueryException;
-import org.hibernate.MappingException;
import org.hibernate.engine.JoinSequence;
import org.hibernate.hql.QueryTranslator;
import org.hibernate.hql.CollectionProperties;
@@ -285,11 +284,19 @@
throw new IllegalStateException( "No table alias for node " + this );
}
String[] cols;
+ String propertyName;
+ if ( getEntityPersister() != null && getEntityPersister().getEntityMetamodel() != null
+ && getEntityPersister().getEntityMetamodel().hasNonIdentifierPropertyNamedId() ) {
+ propertyName = getEntityPersister().getIdentifierPropertyName();
+ }
+ else {
+ propertyName = EntityPersister.ENTITY_ID;
+ }
if ( getWalker().getStatementType() == HqlSqlWalker.SELECT ) {
- cols = getPropertyMapping( EntityPersister.ENTITY_ID ).toColumns( table, EntityPersister.ENTITY_ID );
+ cols = getPropertyMapping( propertyName ).toColumns( table, propertyName );
}
else {
- cols = getPropertyMapping( EntityPersister.ENTITY_ID ).toColumns( EntityPersister.ENTITY_ID );
+ cols = getPropertyMapping( propertyName ).toColumns( propertyName );
}
String result = StringHelper.join( ", ", cols );
return cols.length == 1 ? result : "(" + result + ")";
@@ -375,13 +382,6 @@
return origin;
}
- /**
- * Returns the type of a property, given it's name (the last part) and the full path.
- *
- * @param propertyName The last part of the full path to the property.
- * @return The type.
- * @0param propertyPath The full property path.
- */
public Type getPropertyType(String propertyName, String propertyPath) {
return elementType.getPropertyType( propertyName, propertyPath );
}
@@ -422,9 +422,6 @@
return filter;
}
- /**
- * Returns true if the from fragment should be included in the from clause.
- */
public boolean useFromFragment() {
checkInitialized();
// If it's not implied or it is implied and it's a many to many join where the target wasn't found.
@@ -472,10 +469,6 @@
// Do nothing, eplicit from elements are *always* in the projection list.
}
- /**
- * Returns true if this element should be in the projection list.
- *
- */
public boolean inProjectionList() {
return !isImplied() && isFromOrJoinFragment();
}
Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/persister/entity/AbstractEntityPersister.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/persister/entity/AbstractEntityPersister.java 2006-11-21 16:33:52 UTC (rev 10850)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/persister/entity/AbstractEntityPersister.java 2006-11-21 17:38:43 UTC (rev 10851)
@@ -1508,9 +1508,11 @@
// ALIASES
internalInitSubclassPropertyAliasesMap( null, model.getSubclassPropertyClosureIterator() );
- // aliases for identifier ( alias.id )
- subclassPropertyAliases.put( ENTITY_ID, getIdentifierAliases() );
- subclassPropertyColumnNames.put( ENTITY_ID, getIdentifierColumnNames() );
+ // aliases for identifier ( alias.id ); skip if the entity defines a non-id property named 'id'
+ if ( ! entityMetamodel.hasNonIdentifierPropertyNamedId() ) {
+ subclassPropertyAliases.put( ENTITY_ID, getIdentifierAliases() );
+ subclassPropertyColumnNames.put( ENTITY_ID, getIdentifierColumnNames() );
+ }
// aliases named identifier ( alias.idname )
if ( hasIdentifierProperty() ) {
@@ -1527,23 +1529,26 @@
String[] idColumnNames = getIdentifierColumnNames();
for ( int i = 0; i < idPropertyNames.length; i++ ) {
- subclassPropertyAliases.put(
- ENTITY_ID + "." + idPropertyNames[i],
- new String[] { idAliases[i] }
+ if ( entityMetamodel.hasNonIdentifierPropertyNamedId() ) {
+ subclassPropertyAliases.put(
+ ENTITY_ID + "." + idPropertyNames[i],
+ new String[] { idAliases[i] }
);
- subclassPropertyColumnNames.put(
- ENTITY_ID + "." + getIdentifierPropertyName() + "." + idPropertyNames[i],
- new String[] { idColumnNames[i] }
+ subclassPropertyColumnNames.put(
+ ENTITY_ID + "." + getIdentifierPropertyName() + "." + idPropertyNames[i],
+ new String[] { idColumnNames[i] }
);
- if (hasIdentifierProperty() && !ENTITY_ID.equals( getIdentifierPropertyName() ) ) {
+ }
+// if (hasIdentifierProperty() && !ENTITY_ID.equals( getIdentifierPropertyName() ) ) {
+ if ( hasIdentifierProperty() ) {
subclassPropertyAliases.put(
getIdentifierPropertyName() + "." + idPropertyNames[i],
new String[] { idAliases[i] }
- );
+ );
subclassPropertyColumnNames.put(
getIdentifierPropertyName() + "." + idPropertyNames[i],
new String[] { idColumnNames[i] }
- );
+ );
}
else {
// embedded composite ids ( alias.idname1, alias.idname2 )
@@ -1554,10 +1559,8 @@
}
if ( entityMetamodel.isPolymorphic() ) {
- subclassPropertyAliases.put( ENTITY_CLASS,
- new String[]{getDiscriminatorAlias()} );
- subclassPropertyColumnNames.put( ENTITY_CLASS,
- new String[]{getDiscriminatorColumnName()} );
+ subclassPropertyAliases.put( ENTITY_CLASS, new String[] { getDiscriminatorAlias() } );
+ subclassPropertyColumnNames.put( ENTITY_CLASS, new String[] { getDiscriminatorColumnName() } );
}
}
@@ -1672,7 +1675,9 @@
if ( entityMetamodel.getIdentifierProperty().isEmbedded() ) {
propertyMapping.initPropertyPaths( null, getIdentifierType(), getIdentifierColumnNames(), null, mapping );
}
- propertyMapping.initPropertyPaths( ENTITY_ID, getIdentifierType(), getIdentifierColumnNames(), null, mapping );
+ if ( ! entityMetamodel.hasNonIdentifierPropertyNamedId() ) {
+ propertyMapping.initPropertyPaths( ENTITY_ID, getIdentifierType(), getIdentifierColumnNames(), null, mapping );
+ }
}
private void initDiscriminatorPropertyPath(Mapping mapping) throws MappingException {
@@ -3145,7 +3150,7 @@
return factory;
}
- protected EntityMetamodel getEntityMetamodel() {
+ public EntityMetamodel getEntityMetamodel() {
return entityMetamodel;
}
Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/persister/entity/AbstractPropertyMapping.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/persister/entity/AbstractPropertyMapping.java 2006-11-21 16:33:52 UTC (rev 10850)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/persister/entity/AbstractPropertyMapping.java 2006-11-21 17:38:43 UTC (rev 10851)
@@ -34,18 +34,14 @@
public Type toType(String propertyName) throws QueryException {
Type type = (Type) typesByPropertyPath.get(propertyName);
- if (type==null) throwPropertyException(propertyName);
+ if ( type == null ) {
+ throw propertyException( propertyName );
+ }
return type;
}
- protected final void throwPropertyException(String propertyName)
- throws QueryException {
- throw new QueryException(
- "could not resolve property: " +
- propertyName +
- " of: " +
- getEntityName()
- );
+ protected final QueryException propertyException(String propertyName) {
+ return new QueryException( "could not resolve property: " + propertyName + " of: " + getEntityName() );
}
public String[] getColumnNames(String propertyName) {
@@ -56,11 +52,12 @@
return cols;
}
- public String[] toColumns(String alias, String propertyName)
- throws QueryException {
+ public String[] toColumns(String alias, String propertyName) throws QueryException {
//TODO: *two* hashmap lookups here is one too many...
String[] columns = (String[]) columnsByPropertyPath.get(propertyName);
- if (columns==null) throwPropertyException(propertyName);
+ if ( columns == null ) {
+ throw propertyException( propertyName );
+ }
String[] templates = (String[]) formulaTemplatesByPropertyPath.get(propertyName);
String[] result = new String[columns.length];
for ( int i=0; i<columns.length; i++ ) {
@@ -77,7 +74,9 @@
public String[] toColumns(String propertyName)
throws QueryException {
String[] columns = (String[]) columnsByPropertyPath.get(propertyName);
- if (columns==null) throwPropertyException(propertyName);
+ if ( columns == null ) {
+ throw propertyException( propertyName );
+ }
String[] templates = (String[]) formulaTemplatesByPropertyPath.get(propertyName);
String[] result = new String[columns.length];
for ( int i=0; i<columns.length; i++ ) {
@@ -165,18 +164,20 @@
final String path,
final EntityType etype,
final String[] columns,
- final Mapping factory)
- throws MappingException {
+ final Mapping factory) throws MappingException {
- Type idtype = etype.getIdentifierOrUniqueKeyType(factory);
+ Type idtype = etype.getIdentifierOrUniqueKeyType( factory );
+ String idPropName = etype.getIdentifierOrUniqueKeyPropertyName(factory);
+ boolean hasNonIdentifierPropertyNamedId = hasNonIdentifierPropertyNamedId( etype, factory );
if ( etype.isReferenceToPrimaryKey() ) {
- String idpath1 = extendPath(path, EntityPersister.ENTITY_ID);
- addPropertyPath(idpath1, idtype, columns, null);
- initPropertyPaths(idpath1, idtype, columns, null, factory);
+ if ( !hasNonIdentifierPropertyNamedId ) {
+ String idpath1 = extendPath(path, EntityPersister.ENTITY_ID);
+ addPropertyPath(idpath1, idtype, columns, null);
+ initPropertyPaths(idpath1, idtype, columns, null, factory);
+ }
}
- String idPropName = etype.getIdentifierOrUniqueKeyPropertyName(factory);
if (idPropName!=null) {
String idpath2 = extendPath(path, idPropName);
addPropertyPath(idpath2, idtype, columns, null);
@@ -184,6 +185,18 @@
}
}
+ private boolean hasNonIdentifierPropertyNamedId(final EntityType entityType, final Mapping factory) {
+ // TODO : would be great to have a Mapping#hasNonIdentifierPropertyNamedId method
+ // I don't believe that Mapping#getReferencedPropertyType accounts for the identifier property; so
+ // if it returns for a property named 'id', then we should have a non-id field named id
+ try {
+ return factory.getReferencedPropertyType( entityType.getAssociatedEntityName(), EntityPersister.ENTITY_ID ) != null;
+ }
+ catch( MappingException e ) {
+ return false;
+ }
+ }
+
protected void initComponentPropertyPaths(
final String path,
final AbstractComponentType type,
Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/persister/entity/EntityPersister.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/persister/entity/EntityPersister.java 2006-11-21 16:33:52 UTC (rev 10850)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/persister/entity/EntityPersister.java 2006-11-21 17:38:43 UTC (rev 10851)
@@ -8,6 +8,7 @@
import org.hibernate.LockMode;
import org.hibernate.MappingException;
import org.hibernate.EntityMode;
+import org.hibernate.tuple.entity.EntityMetamodel;
import org.hibernate.cache.CacheConcurrencyStrategy;
import org.hibernate.cache.OptimisticCacheSource;
import org.hibernate.cache.entry.CacheEntryStructure;
@@ -72,8 +73,15 @@
* @return The name of the entity which this persister maps.
*/
public String getEntityName();
-
+
/**
+ * Retrieve the underlying entity metamodel instance...
+ *
+ *@return The metamodel
+ */
+ public EntityMetamodel getEntityMetamodel();
+
+ /**
* Determine whether the given name represents a subclass entity
* (or this entity itself) of the entity mapped by this persister.
*
Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/tuple/entity/EntityMetamodel.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/tuple/entity/EntityMetamodel.java 2006-11-21 16:33:52 UTC (rev 10850)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/tuple/entity/EntityMetamodel.java 2006-11-21 17:38:43 UTC (rev 10851)
@@ -75,6 +75,7 @@
private final boolean hasCollections;
private final boolean hasMutableProperties;
private final boolean hasLazyProperties;
+ private final boolean hasNonIdentifierPropertyNamedId;
private final int[] naturalIdPropertyNumbers;
@@ -151,6 +152,7 @@
boolean foundCascade = false;
boolean foundCollection = false;
boolean foundMutable = false;
+ boolean foundNonIdentifierPropertyNamedId = false;
while ( iter.hasNext() ) {
Property prop = ( Property ) iter.next();
@@ -167,6 +169,10 @@
naturalIdNumbers.add( new Integer(i) );
}
+ if ( "id".equals( prop.getName() ) ) {
+ foundNonIdentifierPropertyNamedId = true;
+ }
+
// temporary ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
boolean lazy = prop.isLazy() && lazyAvailable;
if ( lazy ) hasLazy = true;
@@ -215,9 +221,12 @@
}
hasCascades = foundCascade;
+ hasNonIdentifierPropertyNamedId = foundNonIdentifierPropertyNamedId;
versionPropertyIndex = tempVersionProperty;
hasLazyProperties = hasLazy;
- if (hasLazyProperties) log.info("lazy property fetching available for: " + name);
+ if ( hasLazyProperties ) {
+ log.info( "lazy property fetching available for: " + name );
+ }
lazy = persistentClass.isLazy() && (
// TODO: this disables laziness even in non-pojo entity modes:
@@ -371,6 +380,10 @@
return hasMutableProperties;
}
+ public boolean hasNonIdentifierPropertyNamedId() {
+ return hasNonIdentifierPropertyNamedId;
+ }
+
public boolean hasLazyProperties() {
return hasLazyProperties;
}
Added: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idprops/IdentifierPropertyReferencesTest.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idprops/IdentifierPropertyReferencesTest.java 2006-11-21 16:33:52 UTC (rev 10850)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idprops/IdentifierPropertyReferencesTest.java 2006-11-21 17:38:43 UTC (rev 10851)
@@ -0,0 +1,187 @@
+package org.hibernate.test.idprops;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.test.TestCase;
+import org.hibernate.Session;
+import org.hibernate.Query;
+import org.hibernate.Criteria;
+import org.hibernate.criterion.Projections;
+import org.hibernate.criterion.Restrictions;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class IdentifierPropertyReferencesTest extends TestCase {
+ public IdentifierPropertyReferencesTest(String name) {
+ super( name );
+ }
+
+ protected String[] getMappings() {
+ return new String[] { "idprops/Mapping.hbm.xml" };
+ }
+
+ public static Test suite() {
+ return new TestSuite( IdentifierPropertyReferencesTest.class );
+ }
+
+ public void testHqlIdPropertyReferences() {
+ Session s = openSession();
+ s.beginTransaction();
+ Person p = new Person( new Long(1), "steve", 123 );
+ s.save( p );
+ Order o = new Order( new Long(1), p );
+ LineItem l = new LineItem( o, "my-product", 2 );
+ l.setId( "456" );
+ s.save( o );
+ s.getTransaction().commit();
+ s.close();
+
+ s = openSession();
+ s.beginTransaction();
+
+ long count = extractCount( s, "select count(*) from Person p where p.id = 123" );
+ assertEquals( "Person by id prop (non-identifier)", 1, count );
+ count = extractCount( s, "select count(*) from Person p where p.pk = 1" );
+ assertEquals( "Person by pk prop (identifier)", 1, count );
+
+ count = extractCount( s, "select count(*) from Order o where o.id = 1" );
+ assertEquals( "Order by number prop (named identifier)", 1, count );
+ count = extractCount( s, "select count(*) from Order o where o.number = 1" );
+ assertEquals( "Order by id prop (virtual identifier)", 1, count );
+
+ count = extractCount( s, "select count(*) from LineItem l where l.id = '456'" );
+ assertEquals( "LineItem by id prop (non-identifier", 1, count );
+
+ if ( getDialect().supportsRowValueConstructorSyntax() ) {
+ Query q = s.createQuery( "select count(*) from LineItem l where l.pk = (:order, :product)" )
+ .setEntity( "order", o )
+ .setString( "product", "my-product" );
+ count = extractCount( q );
+ assertEquals( "LineItem by pk prop (named composite identifier", 1, count );
+ }
+
+ count = extractCount( s, "select count(*) from Order o where o.orderee.id = 1" );
+ assertEquals( 0, count );
+ count = extractCount( s, "select count(*) from Order o where o.orderee.pk = 1" );
+ assertEquals( 1, count );
+ count = extractCount( s, "select count(*) from Order o where o.orderee.id = 123" );
+ assertEquals( 1, count );
+
+ count = extractCount( s, "select count(*) from LineItem l where l.pk.order.id = 1" );
+ assertEquals( 1, count );
+ count = extractCount( s, "select count(*) from LineItem l where l.pk.order.number = 1" );
+ assertEquals( 1, count );
+ count = extractCount( s, "select count(*) from LineItem l where l.pk.order.orderee.pk = 1" );
+ assertEquals( 1, count );
+
+ s.delete( o );
+ s.delete( p );
+ s.getTransaction().commit();
+ s.close();
+ }
+
+ public void testCriteriaIdPropertyReferences() {
+ Session s = openSession();
+ s.beginTransaction();
+ Person p = new Person( new Long(1), "steve", 123 );
+ s.save( p );
+ Order o = new Order( new Long(1), p );
+ LineItem l = new LineItem( o, "my-product", 2 );
+ l.setId( "456" );
+ s.save( o );
+ s.getTransaction().commit();
+ s.close();
+
+ s = openSession();
+ s.beginTransaction();
+
+ Criteria crit = s.createCriteria( Person.class );
+ crit.setProjection( Projections.rowCount() );
+ crit.add( Restrictions.eq( "id", new Integer(123) ) );
+ long count = extractCount( crit );
+ assertEquals( "Person by id prop (non-identifier)", 1, count );
+
+ crit = s.createCriteria( Person.class );
+ crit.setProjection( Projections.rowCount() );
+ crit.add( Restrictions.eq( "pk", new Long(1) ) );
+ count = extractCount( crit );
+ assertEquals( "Person by pk prop (identifier)", 1, count );
+
+ crit = s.createCriteria( Order.class );
+ crit.setProjection( Projections.rowCount() );
+ crit.add( Restrictions.eq( "number", new Long(1) ) );
+ count = extractCount( crit );
+ assertEquals( "Order by number prop (named identifier)", 1, count );
+
+ crit = s.createCriteria( Order.class );
+ crit.setProjection( Projections.rowCount() );
+ crit.add( Restrictions.eq( "id", new Long(1) ) );
+ count = extractCount( crit );
+ assertEquals( "Order by id prop (virtual identifier)", 1, count );
+
+ crit = s.createCriteria( LineItem.class );
+ crit.setProjection( Projections.rowCount() );
+ crit.add( Restrictions.eq( "id", "456" ) );
+ count = extractCount( crit );
+ assertEquals( "LineItem by id prop (non-identifier", 1, count );
+
+ if ( getDialect().supportsRowValueConstructorSyntax() ) {
+ crit = s.createCriteria( LineItem.class );
+ crit.setProjection( Projections.rowCount() );
+ crit.add( Restrictions.eq( "pk", new LineItemPK( o, "my-product" ) ) );
+ count = extractCount( crit );
+ assertEquals( "LineItem by pk prop (named composite identifier)", 1, count );
+ }
+
+ crit = s.createCriteria( Order.class );
+ crit.setProjection( Projections.rowCount() );
+ crit.createAlias( "orderee", "p" ).add( Restrictions.eq( "p.id", new Integer(1) ) );
+ count = extractCount( crit );
+ assertEquals( 0, count );
+
+ crit = s.createCriteria( Order.class );
+ crit.setProjection( Projections.rowCount() );
+ crit.createAlias( "orderee", "p" ).add( Restrictions.eq( "p.pk", new Long(1) ) );
+ count = extractCount( crit );
+ assertEquals( 1, count );
+
+ crit = s.createCriteria( Order.class );
+ crit.setProjection( Projections.rowCount() );
+ crit.createAlias( "orderee", "p" ).add( Restrictions.eq( "p.id", new Integer(123) ) );
+ count = extractCount( crit );
+ assertEquals( 1, count );
+
+ crit = s.createCriteria( LineItem.class );
+ crit.setProjection( Projections.rowCount() );
+ crit.add( Restrictions.eq( "pk.order.id", new Long(1) ) );
+ count = extractCount( crit );
+ assertEquals( 1, count );
+
+ crit = s.createCriteria( LineItem.class );
+ crit.setProjection( Projections.rowCount() );
+ crit.add( Restrictions.eq( "pk.order.number", new Long(1) ) );
+ count = extractCount( crit );
+ assertEquals( 1, count );
+
+ s.delete( o );
+ s.delete( p );
+ s.getTransaction().commit();
+ s.close();
+ }
+
+ private long extractCount(Session s, String hql) {
+ return extractCount( s.createQuery( hql ) );
+ }
+
+ private long extractCount(Query query) {
+ return ( ( Long ) query.list().get( 0 ) ).longValue();
+ }
+
+ private long extractCount(Criteria crit) {
+ return ( ( Integer ) crit.list().get( 0 ) ).intValue();
+ }
+}
Added: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idprops/LineItem.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idprops/LineItem.java 2006-11-21 16:33:52 UTC (rev 10850)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idprops/LineItem.java 2006-11-21 17:38:43 UTC (rev 10851)
@@ -0,0 +1,49 @@
+package org.hibernate.test.idprops;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class LineItem {
+ private LineItemPK pk;
+ private int quantity;
+ private String id;
+
+ public LineItem() {
+ }
+
+ public LineItem(LineItemPK pk, int quantity) {
+ this.pk = pk;
+ this.quantity = quantity;
+ this.pk.getOrder().getLineItems().add( this );
+ }
+
+ public LineItem(Order order, String productCode, int quantity) {
+ this( new LineItemPK( order, productCode ), quantity );
+ }
+
+ public LineItemPK getPk() {
+ return pk;
+ }
+
+ public void setPk(LineItemPK pk) {
+ this.pk = pk;
+ }
+
+ public int getQuantity() {
+ return quantity;
+ }
+
+ public void setQuantity(int quantity) {
+ this.quantity = quantity;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+}
Added: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idprops/LineItemPK.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idprops/LineItemPK.java 2006-11-21 16:33:52 UTC (rev 10850)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idprops/LineItemPK.java 2006-11-21 17:38:43 UTC (rev 10851)
@@ -0,0 +1,64 @@
+package org.hibernate.test.idprops;
+
+import java.io.Serializable;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class LineItemPK implements Serializable {
+ private Order order;
+ private String productCode;
+
+ public LineItemPK() {
+ }
+
+ public LineItemPK(Order order, String productCode) {
+ this.order = order;
+ this.productCode = productCode;
+ }
+
+ public Order getOrder() {
+ return order;
+ }
+
+ public void setOrder(Order order) {
+ this.order = order;
+ }
+
+ public String getProductCode() {
+ return productCode;
+ }
+
+ public void setProductCode(String productCode) {
+ this.productCode = productCode;
+ }
+
+ public boolean equals(Object o) {
+ if ( this == o ) {
+ return true;
+ }
+ if ( o == null || getClass() != o.getClass() ) {
+ return false;
+ }
+
+ LineItemPK that = ( LineItemPK ) o;
+
+ if ( !order.equals( that.order ) ) {
+ return false;
+ }
+ if ( !productCode.equals( that.productCode ) ) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public int hashCode() {
+ int result;
+ result = order.hashCode();
+ result = 31 * result + productCode.hashCode();
+ return result;
+ }
+}
Added: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idprops/Mapping.hbm.xml
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idprops/Mapping.hbm.xml 2006-11-21 16:33:52 UTC (rev 10850)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idprops/Mapping.hbm.xml 2006-11-21 17:38:43 UTC (rev 10851)
@@ -0,0 +1,48 @@
+<?xml version="1.0"?>
+
+<!DOCTYPE hibernate-mapping SYSTEM "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
+
+<hibernate-mapping package="org.hibernate.test.idprops">
+
+ <!--
+ Person has an identitifer property named something other than 'id';
+ additionally, it has a non-identitifer property named 'id'
+ -->
+ <class name="Person" table="T_ID_PERSON">
+ <id name="pk" column="PK" type="long">
+ <generator class="assigned"/>
+ </id>
+ <property name="name" column="NAME" type="string"/>
+ <property name="id" column="ID_NON_ID" type="int" />
+ </class>
+
+ <!--
+ Order has an identitifer property named something other than 'id';
+ it has no non-identitifer property named 'id'
+ -->
+ <class name="Order" table="T_ID_ORDER">
+ <id name="number" column="PK" type="long">
+ <generator class="assigned"/>
+ </id>
+ <property name="placed" column="ORDR_DT" type="timestamp"/>
+ <many-to-one name="orderee" class="Person" column="ORDEREE"/>
+ <set name="lineItems" cascade="all-delete-orphan" lazy="true" inverse="true">
+ <key column="ORDR_ID"/>
+ <one-to-many class="LineItem"/>
+ </set>
+ </class>
+
+ <!--
+ LineItem has a composite identitifer property named something other than 'id';
+ additionally, it has a non-identitifer property named 'id'
+ -->
+ <class name="LineItem" table="T_ID_LINE_ITEM">
+ <composite-id class="LineItemPK" name="pk">
+ <key-many-to-one name="order" class="Order" column="ORDR_ID" />
+ <key-property name="productCode" column="PROD_CODE" type="string"/>
+ </composite-id>
+ <property name="quantity" column="QTY" type="int"/>
+ <property name="id" column="ID_NON_ID2" type="string"/>
+ </class>
+
+</hibernate-mapping>
\ No newline at end of file
Added: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idprops/Order.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idprops/Order.java 2006-11-21 16:33:52 UTC (rev 10850)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idprops/Order.java 2006-11-21 17:38:43 UTC (rev 10851)
@@ -0,0 +1,60 @@
+package org.hibernate.test.idprops;
+
+import java.util.Date;
+import java.util.Set;
+import java.util.HashSet;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class Order {
+ private Long number;
+ private Date placed;
+ private Person orderee;
+
+ private Set lineItems = new HashSet();
+
+ public Order() {
+ }
+
+ public Order(Long number, Person orderee) {
+ this.number = number;
+ this.orderee = orderee;
+ this.placed = new Date();
+ }
+
+ public Long getNumber() {
+ return number;
+ }
+
+ public void setNumber(Long number) {
+ this.number = number;
+ }
+
+ public Date getPlaced() {
+ return placed;
+ }
+
+ public void setPlaced(Date placed) {
+ this.placed = placed;
+ }
+
+ public Person getOrderee() {
+ return orderee;
+ }
+
+ public void setOrderee(Person orderee) {
+ this.orderee = orderee;
+ }
+
+
+ public Set getLineItems() {
+ return lineItems;
+ }
+
+ public void setLineItems(Set lineItems) {
+ this.lineItems = lineItems;
+ }
+}
Added: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idprops/Person.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idprops/Person.java 2006-11-21 16:33:52 UTC (rev 10850)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/idprops/Person.java 2006-11-21 17:38:43 UTC (rev 10851)
@@ -0,0 +1,45 @@
+package org.hibernate.test.idprops;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class Person {
+ private Long pk;
+ private String name;
+ private int id;
+
+ public Person() {
+ }
+
+ public Person(Long pk, String name, int id) {
+ this.pk = pk;
+ this.name = name;
+ this.id = id;
+ }
+
+ public Long getPk() {
+ return pk;
+ }
+
+ public void setPk(Long pk) {
+ this.pk = pk;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+}
Modified: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/legacy/CustomPersister.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/legacy/CustomPersister.java 2006-11-21 16:33:52 UTC (rev 10850)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/legacy/CustomPersister.java 2006-11-21 17:38:43 UTC (rev 10851)
@@ -11,6 +11,7 @@
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.MappingException;
+import org.hibernate.tuple.entity.EntityMetamodel;
import org.hibernate.cache.CacheConcurrencyStrategy;
import org.hibernate.cache.entry.CacheEntryStructure;
import org.hibernate.cache.entry.UnstructuredCacheEntry;
@@ -616,4 +617,8 @@
public Comparator getVersionComparator() {
return null;
}
+
+ public EntityMetamodel getEntityMetamodel() {
+ return null;
+ }
}
18 years, 1 month
Hibernate SVN: r10850 - branches/Branch_3_2/Hibernate3/test/org/hibernate/test/hql
by hibernate-commits@lists.jboss.org
Author: steve.ebersole(a)jboss.com
Date: 2006-11-21 11:33:52 -0500 (Tue, 21 Nov 2006)
New Revision: 10850
Modified:
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/hql/ASTParserLoadingTest.java
Log:
more component type queries
Modified: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/hql/ASTParserLoadingTest.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/hql/ASTParserLoadingTest.java 2006-11-21 16:33:38 UTC (rev 10849)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/hql/ASTParserLoadingTest.java 2006-11-21 16:33:52 UTC (rev 10850)
@@ -45,6 +45,7 @@
import org.hibernate.transform.Transformers;
import org.hibernate.type.ManyToOneType;
import org.hibernate.type.Type;
+import org.hibernate.type.ComponentType;
import org.hibernate.util.StringHelper;
/**
@@ -173,6 +174,10 @@
Session s = openSession();
s.beginTransaction();
+ Type[] types = s.createQuery( "select h.name from Human h" ).getReturnTypes();
+ assertEquals( 1, types.length );
+ assertTrue( types[0] instanceof ComponentType );
+
// Test the ability to perform comparisions between component values
s.createQuery( "from Human h where h.name = h.name" ).list();
s.createQuery( "from Human h where h.name = :name" ).setParameter( "name", new Name() ).list();
@@ -186,6 +191,8 @@
s.createQuery( "from Human h where ('John', 'X', 'Doe') <> h.name" ).list();
s.createQuery( "from Human h where ('John', 'X', 'Doe') >= h.name" ).list();
+ s.createQuery( "from Human h order by h.name" ).list();
+
s.getTransaction().commit();
s.close();
}
18 years, 1 month
Hibernate SVN: r10849 - trunk/Hibernate3/test/org/hibernate/test/hql
by hibernate-commits@lists.jboss.org
Author: steve.ebersole(a)jboss.com
Date: 2006-11-21 11:33:38 -0500 (Tue, 21 Nov 2006)
New Revision: 10849
Modified:
trunk/Hibernate3/test/org/hibernate/test/hql/ASTParserLoadingTest.java
Log:
more component type queries
Modified: trunk/Hibernate3/test/org/hibernate/test/hql/ASTParserLoadingTest.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/hql/ASTParserLoadingTest.java 2006-11-21 16:05:39 UTC (rev 10848)
+++ trunk/Hibernate3/test/org/hibernate/test/hql/ASTParserLoadingTest.java 2006-11-21 16:33:38 UTC (rev 10849)
@@ -45,6 +45,7 @@
import org.hibernate.transform.Transformers;
import org.hibernate.type.ManyToOneType;
import org.hibernate.type.Type;
+import org.hibernate.type.ComponentType;
import org.hibernate.util.StringHelper;
/**
@@ -173,6 +174,10 @@
Session s = openSession();
s.beginTransaction();
+ Type[] types = s.createQuery( "select h.name from Human h" ).getReturnTypes();
+ assertEquals( 1, types.length );
+ assertTrue( types[0] instanceof ComponentType );
+
// Test the ability to perform comparisions between component values
s.createQuery( "from Human h where h.name = h.name" ).list();
s.createQuery( "from Human h where h.name = :name" ).setParameter( "name", new Name() ).list();
@@ -186,6 +191,8 @@
s.createQuery( "from Human h where ('John', 'X', 'Doe') <> h.name" ).list();
s.createQuery( "from Human h where ('John', 'X', 'Doe') >= h.name" ).list();
+ s.createQuery( "from Human h order by h.name" ).list();
+
s.getTransaction().commit();
s.close();
}
18 years, 1 month
Hibernate SVN: r10848 - in trunk/Hibernate3/test/org/hibernate/test: . lob
by hibernate-commits@lists.jboss.org
Author: steve.ebersole(a)jboss.com
Date: 2006-11-21 11:05:39 -0500 (Tue, 21 Nov 2006)
New Revision: 10848
Added:
trunk/Hibernate3/test/org/hibernate/test/lob/BlobTest.java
trunk/Hibernate3/test/org/hibernate/test/lob/LobHolder.java
trunk/Hibernate3/test/org/hibernate/test/lob/LobMappings.hbm.xml
trunk/Hibernate3/test/org/hibernate/test/lob/LobSuite.java
trunk/Hibernate3/test/org/hibernate/test/lob/MaterializedBlobType.java
trunk/Hibernate3/test/org/hibernate/test/lob/SerializableTypeTest.java
Removed:
trunk/Hibernate3/test/org/hibernate/test/lob/ClobHoldingEntity.hbm.xml
trunk/Hibernate3/test/org/hibernate/test/lob/ClobHoldingEntity.java
trunk/Hibernate3/test/org/hibernate/test/lob/LobTest.java
trunk/Hibernate3/test/org/hibernate/test/lob/Name.java
trunk/Hibernate3/test/org/hibernate/test/lob/User.hbm.xml
trunk/Hibernate3/test/org/hibernate/test/lob/User.java
Modified:
trunk/Hibernate3/test/org/hibernate/test/AllTests.java
trunk/Hibernate3/test/org/hibernate/test/lob/ClobTest.java
Log:
lob testing
Modified: trunk/Hibernate3/test/org/hibernate/test/AllTests.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/AllTests.java 2006-11-21 16:04:45 UTC (rev 10847)
+++ trunk/Hibernate3/test/org/hibernate/test/AllTests.java 2006-11-21 16:05:39 UTC (rev 10848)
@@ -83,8 +83,7 @@
import org.hibernate.test.legacy.SQLFunctionsTest;
import org.hibernate.test.legacy.SQLLoaderTest;
import org.hibernate.test.legacy.StatisticsTest;
-import org.hibernate.test.lob.ClobTest;
-import org.hibernate.test.lob.LobTest;
+import org.hibernate.test.lob.LobSuite;
import org.hibernate.test.manytomany.ManyToManyTest;
import org.hibernate.test.map.MapIndexFormulaTest;
import org.hibernate.test.mapcompelem.MapCompositeElementTest;
@@ -292,8 +291,7 @@
suite.addTest( UtilSuite.suite() );
suite.addTest( AnyTypeTest.suite() );
suite.addTest( SQLFunctionsInterSystemsTest.suite() );
- suite.addTest( LobTest.suite() );
- suite.addTest( ClobTest.suite() );
+ suite.addTest( LobSuite.suite() );
return filter( suite );
//return suite;
Added: trunk/Hibernate3/test/org/hibernate/test/lob/BlobTest.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/lob/BlobTest.java 2006-11-21 16:04:45 UTC (rev 10847)
+++ trunk/Hibernate3/test/org/hibernate/test/lob/BlobTest.java 2006-11-21 16:05:39 UTC (rev 10848)
@@ -0,0 +1,196 @@
+package org.hibernate.test.lob;
+
+import java.sql.Blob;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import junit.framework.AssertionFailedError;
+
+import org.hibernate.test.DatabaseSpecificTestCase;
+import org.hibernate.Session;
+import org.hibernate.Hibernate;
+import org.hibernate.LockMode;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.util.ArrayHelper;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class BlobTest extends DatabaseSpecificTestCase {
+ private static final int BLOB_SIZE = 10000;
+
+ public BlobTest(String name) {
+ super( name );
+ }
+
+ protected String[] getMappings() {
+ return new String[] { "lob/LobMappings.hbm.xml" };
+ }
+
+ public static Test suite() {
+ return new TestSuite( BlobTest.class );
+ }
+
+ public boolean appliesTo(Dialect dialect) {
+ return supportsExpectedLobUsagePattern();
+ }
+
+ public void testBoundedMaterializedBlobAccess() {
+ byte[] original = buildRecursively( BLOB_SIZE, true );
+ byte[] changed = buildRecursively( BLOB_SIZE, false );
+
+ Session s = openSession();
+ s.beginTransaction();
+ LobHolder entity = new LobHolder();
+ entity.setMaterializedBlob( original );
+ s.save( entity );
+ s.getTransaction().commit();
+ s.close();
+
+ s = openSession();
+ s.beginTransaction();
+ entity = ( LobHolder ) s.get( LobHolder.class, entity.getId() );
+ assertEquals( BLOB_SIZE, entity.getMaterializedBlob().length );
+ assertEquals( original, entity.getMaterializedBlob() );
+ entity.setMaterializedBlob( changed );
+ s.getTransaction().commit();
+ s.close();
+
+ s = openSession();
+ s.beginTransaction();
+ entity = ( LobHolder ) s.get( LobHolder.class, entity.getId() );
+ assertEquals( BLOB_SIZE, entity.getMaterializedBlob().length );
+ assertEquals( changed, entity.getMaterializedBlob() );
+ s.delete( entity );
+ s.getTransaction().commit();
+ s.close();
+ }
+
+ public void testBoundedBlobLocatorAccess() throws Throwable {
+ byte[] original = buildRecursively( BLOB_SIZE, true );
+ byte[] changed = buildRecursively( BLOB_SIZE, false );
+
+ Session s = openSession();
+ s.beginTransaction();
+ LobHolder entity = new LobHolder();
+ entity.setBlobLocator( Hibernate.createBlob( original ) );
+ s.save( entity );
+ s.getTransaction().commit();
+ s.close();
+
+ s = openSession();
+ s.beginTransaction();
+ entity = ( LobHolder ) s.get( LobHolder.class, entity.getId() );
+ assertEquals( BLOB_SIZE, entity.getBlobLocator().length() );
+ assertEquals( original, extractData( entity.getBlobLocator() ) );
+ s.getTransaction().commit();
+ s.close();
+
+ // test mutation via setting the new clob data...
+ if ( supportsLobValueChangePropogation() ) {
+ s = openSession();
+ s.beginTransaction();
+ entity = ( LobHolder ) s.get( LobHolder.class, entity.getId(), LockMode.UPGRADE );
+ entity.getBlobLocator().truncate( 1 );
+ entity.getBlobLocator().setBytes( 1, changed );
+ s.getTransaction().commit();
+ s.close();
+
+ s = openSession();
+ s.beginTransaction();
+ entity = ( LobHolder ) s.get( LobHolder.class, entity.getId(), LockMode.UPGRADE );
+ assertNotNull( entity.getBlobLocator() );
+ assertEquals( BLOB_SIZE, entity.getBlobLocator().length() );
+ assertEquals( changed, extractData( entity.getBlobLocator() ) );
+ entity.getBlobLocator().truncate( 1 );
+ entity.getBlobLocator().setBytes( 1, original );
+ s.getTransaction().commit();
+ s.close();
+ }
+
+ // test mutation via supplying a new clob locator instance...
+ s = openSession();
+ s.beginTransaction();
+ entity = ( LobHolder ) s.get( LobHolder.class, entity.getId(), LockMode.UPGRADE );
+ assertNotNull( entity.getBlobLocator() );
+ assertEquals( BLOB_SIZE, entity.getBlobLocator().length() );
+ assertEquals( original, extractData( entity.getBlobLocator() ) );
+ entity.setBlobLocator( Hibernate.createBlob( changed ) );
+ s.getTransaction().commit();
+ s.close();
+
+ s = openSession();
+ s.beginTransaction();
+ entity = ( LobHolder ) s.get( LobHolder.class, entity.getId() );
+ assertEquals( BLOB_SIZE, entity.getBlobLocator().length() );
+ assertEquals( changed, extractData( entity.getBlobLocator() ) );
+ s.delete( entity );
+ s.getTransaction().commit();
+ s.close();
+
+ }
+
+ public void testUnboundedBlobLocatorAccess() throws Throwable {
+ if ( ! supportsUnboundedLobLocatorMaterialization() ) {
+ return;
+ }
+
+ // Note: unbounded mutation of the underlying lob data is completely
+ // unsupported; most databases would not allow such a construct anyway.
+ // Thus here we are only testing materialization...
+
+ byte[] original = buildRecursively( BLOB_SIZE, true );
+
+ Session s = openSession();
+ s.beginTransaction();
+ LobHolder entity = new LobHolder();
+ entity.setBlobLocator( Hibernate.createBlob( original ) );
+ s.save( entity );
+ s.getTransaction().commit();
+ s.close();
+
+ // load the entity with the clob locator, and close the session/transaction;
+ // at that point it is unbounded...
+ s = openSession();
+ s.beginTransaction();
+ entity = ( LobHolder ) s.get( LobHolder.class, entity.getId() );
+ s.getTransaction().commit();
+ s.close();
+
+ assertEquals( BLOB_SIZE, entity.getBlobLocator().length() );
+ assertEquals( original, extractData( entity.getBlobLocator() ) );
+
+ s = openSession();
+ s.beginTransaction();
+ s.delete( entity );
+ s.getTransaction().commit();
+ s.close();
+ }
+
+ private byte[] extractData(Blob blob) throws Throwable {
+ return blob.getBytes( 1, ( int ) blob.length() );
+ }
+
+
+ private byte[] buildRecursively(int size, boolean on) {
+ byte[] data = new byte[size];
+ data[0] = mask( on );
+ for ( int i = 0; i < size; i++ ) {
+ data[i] = mask( on );
+ on = !on;
+ }
+ return data;
+ }
+
+ private byte mask(boolean on) {
+ return on ? ( byte ) 1 : ( byte ) 0;
+ }
+
+ public static void assertEquals(byte[] val1, byte[] val2) {
+ if ( !ArrayHelper.isEquals( val1, val2 ) ) {
+ throw new AssertionFailedError( "byte arrays did not match" );
+ }
+ }
+}
Deleted: trunk/Hibernate3/test/org/hibernate/test/lob/ClobHoldingEntity.hbm.xml
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/lob/ClobHoldingEntity.hbm.xml 2006-11-21 16:04:45 UTC (rev 10847)
+++ trunk/Hibernate3/test/org/hibernate/test/lob/ClobHoldingEntity.hbm.xml 2006-11-21 16:05:39 UTC (rev 10848)
@@ -1,16 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE hibernate-mapping PUBLIC
- "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
-
-<hibernate-mapping package="org.hibernate.test.lob">
-
- <class name="ClobHoldingEntity" table="CLOB_ENTITY">
- <id name="id" type="long" column="ID">
- <generator class="increment"/>
- </id>
- <property name="serialData" column="SER_DATA" type="text"/>
- <property name="clobData" column="CLOB_DATA" type="clob" />
- </class>
-
-</hibernate-mapping>
\ No newline at end of file
Deleted: trunk/Hibernate3/test/org/hibernate/test/lob/ClobHoldingEntity.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/lob/ClobHoldingEntity.java 2006-11-21 16:04:45 UTC (rev 10847)
+++ trunk/Hibernate3/test/org/hibernate/test/lob/ClobHoldingEntity.java 2006-11-21 16:05:39 UTC (rev 10848)
@@ -1,57 +0,0 @@
-package org.hibernate.test.lob;
-
-import java.sql.Clob;
-
-/**
- * Used to test materialized and lazy-materialized CLOB data.
- * <p/>
- * The {@link #serialData} field is used to hold CLOB data that is
- * materialized into a String immediately (mapped via the
- * Hibernate text type).
- * <p/>
- * The {@link #clobData} field is used to hold CLOB data that is
- * materialized lazily via a JDBC CLOB locator (mapped via
- * the Hibernate clob type).
- *
- * @author Steve Ebersole
- */
-public class ClobHoldingEntity {
- private Long id;
- private String serialData;
- private Clob clobData;
-
- public ClobHoldingEntity() {
- }
-
- public ClobHoldingEntity(String serialData) {
- this.serialData = serialData;
- }
-
- public ClobHoldingEntity(Clob clobData) {
- this.clobData = clobData;
- }
-
- public Long getId() {
- return id;
- }
-
- public void setId(Long id) {
- this.id = id;
- }
-
- public String getSerialData() {
- return serialData;
- }
-
- public void setSerialData(String serialData) {
- this.serialData = serialData;
- }
-
- public Clob getClobData() {
- return clobData;
- }
-
- public void setClobData(Clob clobData) {
- this.clobData = clobData;
- }
-}
Modified: trunk/Hibernate3/test/org/hibernate/test/lob/ClobTest.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/lob/ClobTest.java 2006-11-21 16:04:45 UTC (rev 10847)
+++ trunk/Hibernate3/test/org/hibernate/test/lob/ClobTest.java 2006-11-21 16:05:39 UTC (rev 10848)
@@ -1,16 +1,16 @@
package org.hibernate.test.lob;
import java.sql.Clob;
-import java.io.Reader;
import junit.framework.Test;
import junit.framework.TestSuite;
-import org.hibernate.test.TestCase;
+import org.hibernate.test.DatabaseSpecificTestCase;
import org.hibernate.Session;
import org.hibernate.Hibernate;
import org.hibernate.LockMode;
import org.hibernate.dialect.H2Dialect;
+import org.hibernate.dialect.Dialect;
/**
* Test various access scenarios for eager and lazy materialization
@@ -19,7 +19,7 @@
*
* @author Steve Ebersole
*/
-public class ClobTest extends TestCase {
+public class ClobTest extends DatabaseSpecificTestCase {
private static final int CLOB_SIZE = 10000;
public ClobTest(String name) {
@@ -27,69 +27,65 @@
}
protected String[] getMappings() {
- return new String[] { "lob/ClobHoldingEntity.hbm.xml" };
+ return new String[] { "lob/LobMappings.hbm.xml" };
}
public static Test suite() {
return new TestSuite( ClobTest.class );
}
- public void testBoundedMaterializedClobAccess() {
- if ( !supportsExpectedLobUsagePattern() ) {
- return;
- }
+ public boolean appliesTo(Dialect dialect) {
+ return supportsExpectedLobUsagePattern();
+ }
+ public void testBoundedMaterializedClobAccess() {
String original = buildRecursively( CLOB_SIZE, 'x' );
String changed = buildRecursively( CLOB_SIZE, 'y' );
Session s = openSession();
s.beginTransaction();
- ClobHoldingEntity entity = new ClobHoldingEntity();
- entity.setSerialData( original );
+ LobHolder entity = new LobHolder();
+ entity.setMaterializedClob( original );
s.save( entity );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
- entity = ( ClobHoldingEntity ) s.get( ClobHoldingEntity.class, entity.getId() );
- assertEquals( CLOB_SIZE, entity.getSerialData().length() );
- assertEquals( original, entity.getSerialData() );
- entity.setSerialData( changed );
+ entity = ( LobHolder ) s.get( LobHolder.class, entity.getId() );
+ assertEquals( CLOB_SIZE, entity.getMaterializedClob().length() );
+ assertEquals( original, entity.getMaterializedClob() );
+ entity.setMaterializedClob( changed );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
- entity = ( ClobHoldingEntity ) s.get( ClobHoldingEntity.class, entity.getId() );
- assertEquals( CLOB_SIZE, entity.getSerialData().length() );
- assertEquals( changed, entity.getSerialData() );
+ entity = ( LobHolder ) s.get( LobHolder.class, entity.getId() );
+ assertEquals( CLOB_SIZE, entity.getMaterializedClob().length() );
+ assertEquals( changed, entity.getMaterializedClob() );
s.delete( entity );
s.getTransaction().commit();
s.close();
}
public void testBoundedClobLocatorAccess() throws Throwable {
- if ( !supportsExpectedLobUsagePattern() ) {
- return;
- }
-
String original = buildRecursively( CLOB_SIZE, 'x' );
String changed = buildRecursively( CLOB_SIZE, 'y' );
Session s = openSession();
s.beginTransaction();
- ClobHoldingEntity entity = new ClobHoldingEntity();
- entity.setClobData( Hibernate.createClob( original ) );
+ LobHolder entity = new LobHolder();
+ entity.setClobLocator( Hibernate.createClob( original ) );
s.save( entity );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
- entity = ( ClobHoldingEntity ) s.get( ClobHoldingEntity.class, entity.getId() );
- assertEquals( CLOB_SIZE, entity.getClobData().length() );
- assertEquals( original, extractData( entity.getClobData() ) );
+ entity = ( LobHolder ) s.get( LobHolder.class, entity.getId() );
+ assertEquals( CLOB_SIZE, entity.getClobLocator().length() );
+ assertEquals( original, extractData( entity.getClobLocator() ) );
s.getTransaction().commit();
s.close();
@@ -97,20 +93,20 @@
if ( supportsLobValueChangePropogation() ) {
s = openSession();
s.beginTransaction();
- entity = ( ClobHoldingEntity ) s.get( ClobHoldingEntity.class, entity.getId(), LockMode.UPGRADE );
- entity.getClobData().truncate( 1 );
- entity.getClobData().setString( 1, changed );
+ entity = ( LobHolder ) s.get( LobHolder.class, entity.getId(), LockMode.UPGRADE );
+ entity.getClobLocator().truncate( 1 );
+ entity.getClobLocator().setString( 1, changed );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
- entity = ( ClobHoldingEntity ) s.get( ClobHoldingEntity.class, entity.getId(), LockMode.UPGRADE );
- assertNotNull( entity.getClobData() );
- assertEquals( CLOB_SIZE, entity.getClobData().length() );
- assertEquals( changed, extractData( entity.getClobData() ) );
- entity.getClobData().truncate( 1 );
- entity.getClobData().setString( 1, original );
+ entity = ( LobHolder ) s.get( LobHolder.class, entity.getId(), LockMode.UPGRADE );
+ assertNotNull( entity.getClobLocator() );
+ assertEquals( CLOB_SIZE, entity.getClobLocator().length() );
+ assertEquals( changed, extractData( entity.getClobLocator() ) );
+ entity.getClobLocator().truncate( 1 );
+ entity.getClobLocator().setString( 1, original );
s.getTransaction().commit();
s.close();
}
@@ -118,19 +114,19 @@
// test mutation via supplying a new clob locator instance...
s = openSession();
s.beginTransaction();
- entity = ( ClobHoldingEntity ) s.get( ClobHoldingEntity.class, entity.getId(), LockMode.UPGRADE );
- assertNotNull( entity.getClobData() );
- assertEquals( CLOB_SIZE, entity.getClobData().length() );
- assertEquals( original, extractData( entity.getClobData() ) );
- entity.setClobData( Hibernate.createClob( changed ) );
+ entity = ( LobHolder ) s.get( LobHolder.class, entity.getId(), LockMode.UPGRADE );
+ assertNotNull( entity.getClobLocator() );
+ assertEquals( CLOB_SIZE, entity.getClobLocator().length() );
+ assertEquals( original, extractData( entity.getClobLocator() ) );
+ entity.setClobLocator( Hibernate.createClob( changed ) );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
- entity = ( ClobHoldingEntity ) s.get( ClobHoldingEntity.class, entity.getId() );
- assertEquals( CLOB_SIZE, entity.getClobData().length() );
- assertEquals( changed, extractData( entity.getClobData() ) );
+ entity = ( LobHolder ) s.get( LobHolder.class, entity.getId() );
+ assertEquals( CLOB_SIZE, entity.getClobLocator().length() );
+ assertEquals( changed, extractData( entity.getClobLocator() ) );
s.delete( entity );
s.getTransaction().commit();
s.close();
@@ -138,7 +134,7 @@
}
public void testUnboundedClobLocatorAccess() throws Throwable {
- if ( !supportsExpectedLobUsagePattern() || ! supportsUnboundedLobLocatorMaterialization() ) {
+ if ( ! supportsUnboundedLobLocatorMaterialization() ) {
return;
}
@@ -150,8 +146,8 @@
Session s = openSession();
s.beginTransaction();
- ClobHoldingEntity entity = new ClobHoldingEntity();
- entity.setClobData( Hibernate.createClob( original ) );
+ LobHolder entity = new LobHolder();
+ entity.setClobLocator( Hibernate.createClob( original ) );
s.save( entity );
s.getTransaction().commit();
s.close();
@@ -160,12 +156,12 @@
// at that point it is unbounded...
s = openSession();
s.beginTransaction();
- entity = ( ClobHoldingEntity ) s.get( ClobHoldingEntity.class, entity.getId() );
+ entity = ( LobHolder ) s.get( LobHolder.class, entity.getId() );
s.getTransaction().commit();
s.close();
- assertEquals( CLOB_SIZE, entity.getClobData().length() );
- assertEquals( original, extractData( entity.getClobData() ) );
+ assertEquals( CLOB_SIZE, entity.getClobLocator().length() );
+ assertEquals( original, extractData( entity.getClobLocator() ) );
s = openSession();
s.beginTransaction();
Added: trunk/Hibernate3/test/org/hibernate/test/lob/LobHolder.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/lob/LobHolder.java 2006-11-21 16:04:45 UTC (rev 10847)
+++ trunk/Hibernate3/test/org/hibernate/test/lob/LobHolder.java 2006-11-21 16:05:39 UTC (rev 10848)
@@ -0,0 +1,90 @@
+package org.hibernate.test.lob;
+
+import java.io.Serializable;
+import java.sql.Clob;
+import java.sql.Blob;
+
+/**
+ * An entity containing all kinds of good LOB-type data...
+ * <p/>
+ * {@link #serialData} is used to hold general serializable data which is
+ * mapped via the {@link org.hibernate.type.SerializableType}.
+ * <p/>
+ * {@link #materializedClob} is used to hold CLOB data that is materialized
+ * into a String immediately; it is mapped via the
+ * {@link org.hibernate.type.TextType}.
+ * <p/>
+ * {@link #clobLocator} is used to hold CLOB data that is materialized lazily
+ * via a JDBC CLOB locator; it is mapped via the
+ * {@link org.hibernate.type.ClobType}
+ * <p/>
+ * {@link #materializedBlob} is used to hold BLOB data that is materialized
+ * into a byte array immediately; it is mapped via the
+ * {@link org.hibernate.test.lob.MaterializedBlobType}.
+ * <p/>
+ * {@link #blobLocator} is used to hold BLOB data that is materialized lazily
+ * via a JDBC BLOB locator; it is mapped via the
+ * {@link org.hibernate.type.BlobType}
+ *
+ *
+ * @author Steve Ebersole
+ */
+public class LobHolder {
+ private Long id;
+
+ private Serializable serialData;
+
+ private String materializedClob;
+ private Clob clobLocator;
+
+ private byte[] materializedBlob;
+ private Blob blobLocator;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public Serializable getSerialData() {
+ return serialData;
+ }
+
+ public void setSerialData(Serializable serialData) {
+ this.serialData = serialData;
+ }
+
+ public String getMaterializedClob() {
+ return materializedClob;
+ }
+
+ public void setMaterializedClob(String materializedClob) {
+ this.materializedClob = materializedClob;
+ }
+
+ public Clob getClobLocator() {
+ return clobLocator;
+ }
+
+ public void setClobLocator(Clob clobLocator) {
+ this.clobLocator = clobLocator;
+ }
+
+ public byte[] getMaterializedBlob() {
+ return materializedBlob;
+ }
+
+ public void setMaterializedBlob(byte[] materializedBlob) {
+ this.materializedBlob = materializedBlob;
+ }
+
+ public Blob getBlobLocator() {
+ return blobLocator;
+ }
+
+ public void setBlobLocator(Blob blobLocator) {
+ this.blobLocator = blobLocator;
+ }
+}
Added: trunk/Hibernate3/test/org/hibernate/test/lob/LobMappings.hbm.xml
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/lob/LobMappings.hbm.xml 2006-11-21 16:04:45 UTC (rev 10847)
+++ trunk/Hibernate3/test/org/hibernate/test/lob/LobMappings.hbm.xml 2006-11-21 16:05:39 UTC (rev 10848)
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+ "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
+ "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.lob">
+
+ <class name="LobHolder" table="LOB_ENTITY">
+ <id name="id" type="long" column="ID">
+ <generator class="increment"/>
+ </id>
+
+ <property name="serialData" column="SER_DATA" type="serializable"/>
+
+ <property name="materializedClob" column="MAT_CLOB_DATA" type="text"/>
+ <property name="clobLocator" column="CLOB_DATA" type="clob" />
+
+ <property name="materializedBlob" column="MAT_BLOB_DATA" type="org.hibernate.test.lob.MaterializedBlobType"/>
+ <property name="blobLocator" column="BLOB_DATA" type="blob" />
+ </class>
+
+</hibernate-mapping>
\ No newline at end of file
Added: trunk/Hibernate3/test/org/hibernate/test/lob/LobSuite.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/lob/LobSuite.java 2006-11-21 16:04:45 UTC (rev 10847)
+++ trunk/Hibernate3/test/org/hibernate/test/lob/LobSuite.java 2006-11-21 16:05:39 UTC (rev 10848)
@@ -0,0 +1,19 @@
+package org.hibernate.test.lob;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class LobSuite {
+ public static Test suite() {
+ TestSuite suite = new TestSuite( "LOB handling tests" );
+ suite.addTest( SerializableTypeTest.suite() );
+ suite.addTest( BlobTest.suite() );
+ suite.addTest( ClobTest.suite() );
+ return suite;
+ }
+}
Deleted: trunk/Hibernate3/test/org/hibernate/test/lob/LobTest.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/lob/LobTest.java 2006-11-21 16:04:45 UTC (rev 10847)
+++ trunk/Hibernate3/test/org/hibernate/test/lob/LobTest.java 2006-11-21 16:05:39 UTC (rev 10848)
@@ -1,73 +0,0 @@
-// $Id$
-package org.hibernate.test.lob;
-
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
-import org.hibernate.Session;
-import org.hibernate.Transaction;
-import org.hibernate.test.TestCase;
-
-/**
- * Implementation of DynamicFilterTest.
- *
- * @author Steve
- */
-public class LobTest extends TestCase {
-
- public LobTest(String testName) {
- super(testName);
- }
-
- public void testNewSerializableType() {
- Session session = openSession();
- Transaction txn = session.beginTransaction();
-
- User user = new User();
- user.setEmail("nobody(a)nowhere.com");
- user.setName(new Name());
- user.getName().setFirstName("John");
- user.getName().setInitial(new Character('Q'));
- user.getName().setLastName("Public");
- user.setPassword("password");
- user.setHandle("myHandle");
-
- String payloadText = "Initial payload";
- user.setSerialData( new SerializableData(payloadText) );
-
- session.save(user);
- txn.commit();
-
- session.close();
- user = null;
-
- session = openSession();
- user = (User) session.createQuery("select u from User as u where u.handle = :myHandle")
- .setString("myHandle", "myHandle")
- .uniqueResult();
-
- SerializableData serialData = (SerializableData) user.getSerialData();
- assertTrue(payloadText.equals(serialData.getPayload()));
- session.close();
- }
-
- /**
- * Define the mappings needed for these tests.
- *
- * @return Mappings for these tests.
- */
- protected String[] getMappings() {
- return new String[] {
- "lob/User.hbm.xml"
- };
- }
-
- public String getCacheConcurrencyStrategy() {
- return null;
- }
-
- public static Test suite() {
- return new TestSuite(LobTest.class);
- }
-
-}
Added: trunk/Hibernate3/test/org/hibernate/test/lob/MaterializedBlobType.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/lob/MaterializedBlobType.java 2006-11-21 16:04:45 UTC (rev 10847)
+++ trunk/Hibernate3/test/org/hibernate/test/lob/MaterializedBlobType.java 2006-11-21 16:05:39 UTC (rev 10848)
@@ -0,0 +1,33 @@
+package org.hibernate.test.lob;
+
+import java.sql.Types;
+
+import org.hibernate.type.AbstractBynaryType;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class MaterializedBlobType extends AbstractBynaryType {
+
+ public int sqlType() {
+ return Types.BLOB;
+ }
+
+ public String getName() {
+ return "materialized-blob";
+ }
+
+ public Class getReturnedClass() {
+ return byte[].class;
+ }
+
+ protected Object toExternalFormat(byte[] bytes) {
+ return bytes;
+ }
+
+ protected byte[] toInternalFormat(Object bytes) {
+ return ( byte[] ) bytes;
+ }
+}
Deleted: trunk/Hibernate3/test/org/hibernate/test/lob/Name.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/lob/Name.java 2006-11-21 16:04:45 UTC (rev 10847)
+++ trunk/Hibernate3/test/org/hibernate/test/lob/Name.java 2006-11-21 16:05:39 UTC (rev 10848)
@@ -1,58 +0,0 @@
-// $Id$
-package org.hibernate.test.lob;
-
-import java.io.Serializable;
-
-/**
- * Implementation of Name.
- *
- * @author Steve
- */
-public class Name implements Serializable {
-
- private String firstName;
- private String lastName;
- private Character initial;
-
- public Name() {}
-
- public Name(String first, Character middle, String last) {
- firstName = first;
- initial = middle;
- lastName = last;
- }
-
- public String getFirstName() {
- return firstName;
- }
-
- public void setFirstName(String firstName) {
- this.firstName = firstName;
- }
-
- public Character getInitial() {
- return initial;
- }
-
- public void setInitial(Character initial) {
- this.initial = initial;
- }
-
- public String getLastName() {
- return lastName;
- }
-
- public void setLastName(String lastName) {
- this.lastName = lastName;
- }
-
- public String toString() {
- StringBuffer buf = new StringBuffer()
- .append(firstName)
- .append(' ');
- if (initial!=null) buf.append(initial)
- .append(' ');
- return buf.append(lastName)
- .toString();
- }
-}
Copied: trunk/Hibernate3/test/org/hibernate/test/lob/SerializableTypeTest.java (from rev 10159, trunk/Hibernate3/test/org/hibernate/test/lob/LobTest.java)
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/lob/LobTest.java 2006-07-26 13:36:20 UTC (rev 10159)
+++ trunk/Hibernate3/test/org/hibernate/test/lob/SerializableTypeTest.java 2006-11-21 16:05:39 UTC (rev 10848)
@@ -0,0 +1,55 @@
+// $Id$
+package org.hibernate.test.lob;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.Session;
+import org.hibernate.test.TestCase;
+
+/**
+ * Tests of {@link org.hibernate.type.SerializableType}
+ *
+ * @author Steve Ebersole
+ */
+public class SerializableTypeTest extends TestCase {
+
+ public SerializableTypeTest(String testName) {
+ super( testName );
+ }
+
+ public static Test suite() {
+ return new TestSuite( SerializableTypeTest.class );
+ }
+
+ protected String[] getMappings() {
+ return new String[] { "lob/LobMappings.hbm.xml" };
+ }
+
+ public String getCacheConcurrencyStrategy() {
+ return null;
+ }
+
+ public void testNewSerializableType() {
+ final String payloadText = "Initial payload";
+
+ Session s = openSession();
+ s.beginTransaction();
+ LobHolder holder = new LobHolder();
+ holder.setSerialData( new SerializableData( payloadText ) );
+ s.save( holder );
+ s.getTransaction().commit();
+ s.close();
+
+ s = openSession();
+ s.beginTransaction();
+ holder = ( LobHolder ) s.get( LobHolder.class, holder.getId() );
+ SerializableData serialData = ( SerializableData ) holder.getSerialData();
+ assertEquals( payloadText, serialData.getPayload() );
+ s.delete( holder );
+ s.getTransaction().commit();
+ s.close();
+ }
+
+
+}
Property changes on: trunk/Hibernate3/test/org/hibernate/test/lob/SerializableTypeTest.java
___________________________________________________________________
Name: svn:keywords
+ Author Date Id Revision
Name: svn:eol-style
+ native
Deleted: trunk/Hibernate3/test/org/hibernate/test/lob/User.hbm.xml
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/lob/User.hbm.xml 2006-11-21 16:04:45 UTC (rev 10847)
+++ trunk/Hibernate3/test/org/hibernate/test/lob/User.hbm.xml 2006-11-21 16:05:39 UTC (rev 10848)
@@ -1,34 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE hibernate-mapping PUBLIC
- "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
-
-<hibernate-mapping package="org.hibernate.test.lob">
-
- <class name="User" table="users">
-
- <id name="id" type="long" unsaved-value="null">
- <generator class="increment"/>
- </id>
-
- <!-- We don't change the handle, so map it with update="false". -->
- <property name="handle" unique="true" not-null="true" update="false"/>
-
- <!-- password is a keyword in some databases, so quote it -->
- <property name="password" column="`password`" not-null="true"/>
-
- <property name="email"/>
-
- <property name="serialData" column="ser_data" type="serializable"/>
-
- <!-- Mapping for the component class Name -->
- <component name="name">
- <property name="firstName"/>
- <!-- initial is a keyword in some databases, so quote it -->
- <property name="initial" column="`initial`"/>
- <property name="lastName"/>
- </component>
-
- </class>
-
-</hibernate-mapping>
\ No newline at end of file
Deleted: trunk/Hibernate3/test/org/hibernate/test/lob/User.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/lob/User.java 2006-11-21 16:04:45 UTC (rev 10847)
+++ trunk/Hibernate3/test/org/hibernate/test/lob/User.java 2006-11-21 16:05:39 UTC (rev 10848)
@@ -1,79 +0,0 @@
-// $Id$
-package org.hibernate.test.lob;
-
-import java.io.Serializable;
-
-/**
- * Implementation of User.
- *
- * @author Steve
- */
-public class User implements Serializable {
- private Long id;
- private String handle;
- private String password;
- private Name name;
- private String email;
- private Serializable serialData;
-
- public String getHandle() {
- return handle;
- }
-
- public void setHandle(String handle) {
- this.handle = handle;
- }
-
- public Long getId() {
- return id;
- }
-
- protected void setId(Long id) {
- this.id = id;
- }
-
- public Name getName() {
- return name;
- }
-
- public void setName(Name name) {
- this.name = name;
- }
-
- public String getPassword() {
- return password;
- }
-
- public void setPassword(String password) {
- this.password = password;
- }
-
- public String getEmail() {
- return email;
- }
-
- public void setEmail(String email) {
- this.email = email;
- }
-
- public boolean equals(Object other) {
- if (other==null) return false;
- if ( !(other instanceof User) ) return false;
- return ( (User) other ).getHandle().equals(handle);
- }
-
- public int hashCode() {
- return handle.hashCode();
- }
-
-
- public Serializable getSerialData()
- {
- return serialData;
- }
-
- public void setSerialData(Serializable serialData)
- {
- this.serialData = serialData;
- }
-}
18 years, 1 month
Hibernate SVN: r10847 - in branches/Branch_3_2/Hibernate3/test/org/hibernate/test: . lob
by hibernate-commits@lists.jboss.org
Author: steve.ebersole(a)jboss.com
Date: 2006-11-21 11:04:45 -0500 (Tue, 21 Nov 2006)
New Revision: 10847
Added:
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/BlobTest.java
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/LobHolder.java
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/LobMappings.hbm.xml
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/LobSuite.java
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/MaterializedBlobType.java
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/SerializableTypeTest.java
Removed:
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/ClobHoldingEntity.hbm.xml
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/ClobHoldingEntity.java
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/LobTest.java
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/Name.java
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/User.hbm.xml
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/User.java
Modified:
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/AllTests.java
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/ClobTest.java
Log:
lob testing
Modified: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/AllTests.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/AllTests.java 2006-11-18 04:21:05 UTC (rev 10846)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/AllTests.java 2006-11-21 16:04:45 UTC (rev 10847)
@@ -27,6 +27,7 @@
import org.hibernate.test.criteria.CriteriaQueryTest;
import org.hibernate.test.cuk.CompositePropertyRefTest;
import org.hibernate.test.cut.CompositeUserTypeTest;
+import org.hibernate.test.dialect.cache.SQLFunctionsInterSystemsTest;
import org.hibernate.test.discriminator.DiscriminatorTest;
import org.hibernate.test.dom4j.Dom4jAccessorTest;
import org.hibernate.test.dom4j.Dom4jManyToOneTest;
@@ -82,6 +83,7 @@
import org.hibernate.test.legacy.SQLFunctionsTest;
import org.hibernate.test.legacy.SQLLoaderTest;
import org.hibernate.test.legacy.StatisticsTest;
+import org.hibernate.test.lob.LobSuite;
import org.hibernate.test.manytomany.ManyToManyTest;
import org.hibernate.test.map.MapIndexFormulaTest;
import org.hibernate.test.mapcompelem.MapCompositeElementTest;
@@ -130,9 +132,6 @@
import org.hibernate.test.version.db.DbVersionTest;
import org.hibernate.test.version.sybase.SybaseTimestampVersioningTest;
import org.hibernate.test.where.WhereTest;
-import org.hibernate.test.dialect.cache.SQLFunctionsInterSystemsTest;
-import org.hibernate.test.lob.LobTest;
-import org.hibernate.test.lob.ClobTest;
/**
* @author Gavin King
@@ -292,8 +291,7 @@
suite.addTest( UtilSuite.suite() );
suite.addTest( AnyTypeTest.suite() );
suite.addTest( SQLFunctionsInterSystemsTest.suite() );
- suite.addTest( LobTest.suite() );
- suite.addTest( ClobTest.suite() );
+ suite.addTest( LobSuite.suite() );
return filter( suite );
//return suite;
Added: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/BlobTest.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/BlobTest.java 2006-11-18 04:21:05 UTC (rev 10846)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/BlobTest.java 2006-11-21 16:04:45 UTC (rev 10847)
@@ -0,0 +1,196 @@
+package org.hibernate.test.lob;
+
+import java.sql.Blob;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import junit.framework.AssertionFailedError;
+
+import org.hibernate.test.DatabaseSpecificTestCase;
+import org.hibernate.Session;
+import org.hibernate.Hibernate;
+import org.hibernate.LockMode;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.util.ArrayHelper;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class BlobTest extends DatabaseSpecificTestCase {
+ private static final int BLOB_SIZE = 10000;
+
+ public BlobTest(String name) {
+ super( name );
+ }
+
+ protected String[] getMappings() {
+ return new String[] { "lob/LobMappings.hbm.xml" };
+ }
+
+ public static Test suite() {
+ return new TestSuite( BlobTest.class );
+ }
+
+ public boolean appliesTo(Dialect dialect) {
+ return supportsExpectedLobUsagePattern();
+ }
+
+ public void testBoundedMaterializedBlobAccess() {
+ byte[] original = buildRecursively( BLOB_SIZE, true );
+ byte[] changed = buildRecursively( BLOB_SIZE, false );
+
+ Session s = openSession();
+ s.beginTransaction();
+ LobHolder entity = new LobHolder();
+ entity.setMaterializedBlob( original );
+ s.save( entity );
+ s.getTransaction().commit();
+ s.close();
+
+ s = openSession();
+ s.beginTransaction();
+ entity = ( LobHolder ) s.get( LobHolder.class, entity.getId() );
+ assertEquals( BLOB_SIZE, entity.getMaterializedBlob().length );
+ assertEquals( original, entity.getMaterializedBlob() );
+ entity.setMaterializedBlob( changed );
+ s.getTransaction().commit();
+ s.close();
+
+ s = openSession();
+ s.beginTransaction();
+ entity = ( LobHolder ) s.get( LobHolder.class, entity.getId() );
+ assertEquals( BLOB_SIZE, entity.getMaterializedBlob().length );
+ assertEquals( changed, entity.getMaterializedBlob() );
+ s.delete( entity );
+ s.getTransaction().commit();
+ s.close();
+ }
+
+ public void testBoundedBlobLocatorAccess() throws Throwable {
+ byte[] original = buildRecursively( BLOB_SIZE, true );
+ byte[] changed = buildRecursively( BLOB_SIZE, false );
+
+ Session s = openSession();
+ s.beginTransaction();
+ LobHolder entity = new LobHolder();
+ entity.setBlobLocator( Hibernate.createBlob( original ) );
+ s.save( entity );
+ s.getTransaction().commit();
+ s.close();
+
+ s = openSession();
+ s.beginTransaction();
+ entity = ( LobHolder ) s.get( LobHolder.class, entity.getId() );
+ assertEquals( BLOB_SIZE, entity.getBlobLocator().length() );
+ assertEquals( original, extractData( entity.getBlobLocator() ) );
+ s.getTransaction().commit();
+ s.close();
+
+ // test mutation via setting the new clob data...
+ if ( supportsLobValueChangePropogation() ) {
+ s = openSession();
+ s.beginTransaction();
+ entity = ( LobHolder ) s.get( LobHolder.class, entity.getId(), LockMode.UPGRADE );
+ entity.getBlobLocator().truncate( 1 );
+ entity.getBlobLocator().setBytes( 1, changed );
+ s.getTransaction().commit();
+ s.close();
+
+ s = openSession();
+ s.beginTransaction();
+ entity = ( LobHolder ) s.get( LobHolder.class, entity.getId(), LockMode.UPGRADE );
+ assertNotNull( entity.getBlobLocator() );
+ assertEquals( BLOB_SIZE, entity.getBlobLocator().length() );
+ assertEquals( changed, extractData( entity.getBlobLocator() ) );
+ entity.getBlobLocator().truncate( 1 );
+ entity.getBlobLocator().setBytes( 1, original );
+ s.getTransaction().commit();
+ s.close();
+ }
+
+ // test mutation via supplying a new clob locator instance...
+ s = openSession();
+ s.beginTransaction();
+ entity = ( LobHolder ) s.get( LobHolder.class, entity.getId(), LockMode.UPGRADE );
+ assertNotNull( entity.getBlobLocator() );
+ assertEquals( BLOB_SIZE, entity.getBlobLocator().length() );
+ assertEquals( original, extractData( entity.getBlobLocator() ) );
+ entity.setBlobLocator( Hibernate.createBlob( changed ) );
+ s.getTransaction().commit();
+ s.close();
+
+ s = openSession();
+ s.beginTransaction();
+ entity = ( LobHolder ) s.get( LobHolder.class, entity.getId() );
+ assertEquals( BLOB_SIZE, entity.getBlobLocator().length() );
+ assertEquals( changed, extractData( entity.getBlobLocator() ) );
+ s.delete( entity );
+ s.getTransaction().commit();
+ s.close();
+
+ }
+
+ public void testUnboundedBlobLocatorAccess() throws Throwable {
+ if ( ! supportsUnboundedLobLocatorMaterialization() ) {
+ return;
+ }
+
+ // Note: unbounded mutation of the underlying lob data is completely
+ // unsupported; most databases would not allow such a construct anyway.
+ // Thus here we are only testing materialization...
+
+ byte[] original = buildRecursively( BLOB_SIZE, true );
+
+ Session s = openSession();
+ s.beginTransaction();
+ LobHolder entity = new LobHolder();
+ entity.setBlobLocator( Hibernate.createBlob( original ) );
+ s.save( entity );
+ s.getTransaction().commit();
+ s.close();
+
+ // load the entity with the clob locator, and close the session/transaction;
+ // at that point it is unbounded...
+ s = openSession();
+ s.beginTransaction();
+ entity = ( LobHolder ) s.get( LobHolder.class, entity.getId() );
+ s.getTransaction().commit();
+ s.close();
+
+ assertEquals( BLOB_SIZE, entity.getBlobLocator().length() );
+ assertEquals( original, extractData( entity.getBlobLocator() ) );
+
+ s = openSession();
+ s.beginTransaction();
+ s.delete( entity );
+ s.getTransaction().commit();
+ s.close();
+ }
+
+ private byte[] extractData(Blob blob) throws Throwable {
+ return blob.getBytes( 1, ( int ) blob.length() );
+ }
+
+
+ private byte[] buildRecursively(int size, boolean on) {
+ byte[] data = new byte[size];
+ data[0] = mask( on );
+ for ( int i = 0; i < size; i++ ) {
+ data[i] = mask( on );
+ on = !on;
+ }
+ return data;
+ }
+
+ private byte mask(boolean on) {
+ return on ? ( byte ) 1 : ( byte ) 0;
+ }
+
+ public static void assertEquals(byte[] val1, byte[] val2) {
+ if ( !ArrayHelper.isEquals( val1, val2 ) ) {
+ throw new AssertionFailedError( "byte arrays did not match" );
+ }
+ }
+}
Deleted: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/ClobHoldingEntity.hbm.xml
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/ClobHoldingEntity.hbm.xml 2006-11-18 04:21:05 UTC (rev 10846)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/ClobHoldingEntity.hbm.xml 2006-11-21 16:04:45 UTC (rev 10847)
@@ -1,16 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE hibernate-mapping PUBLIC
- "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
-
-<hibernate-mapping package="org.hibernate.test.lob">
-
- <class name="ClobHoldingEntity" table="CLOB_ENTITY">
- <id name="id" type="long" column="ID">
- <generator class="increment"/>
- </id>
- <property name="serialData" column="SER_DATA" type="text"/>
- <property name="clobData" column="CLOB_DATA" type="clob" />
- </class>
-
-</hibernate-mapping>
\ No newline at end of file
Deleted: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/ClobHoldingEntity.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/ClobHoldingEntity.java 2006-11-18 04:21:05 UTC (rev 10846)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/ClobHoldingEntity.java 2006-11-21 16:04:45 UTC (rev 10847)
@@ -1,57 +0,0 @@
-package org.hibernate.test.lob;
-
-import java.sql.Clob;
-
-/**
- * Used to test materialized and lazy-materialized CLOB data.
- * <p/>
- * The {@link #serialData} field is used to hold CLOB data that is
- * materialized into a String immediately (mapped via the
- * Hibernate text type).
- * <p/>
- * The {@link #clobData} field is used to hold CLOB data that is
- * materialized lazily via a JDBC CLOB locator (mapped via
- * the Hibernate clob type).
- *
- * @author Steve Ebersole
- */
-public class ClobHoldingEntity {
- private Long id;
- private String serialData;
- private Clob clobData;
-
- public ClobHoldingEntity() {
- }
-
- public ClobHoldingEntity(String serialData) {
- this.serialData = serialData;
- }
-
- public ClobHoldingEntity(Clob clobData) {
- this.clobData = clobData;
- }
-
- public Long getId() {
- return id;
- }
-
- public void setId(Long id) {
- this.id = id;
- }
-
- public String getSerialData() {
- return serialData;
- }
-
- public void setSerialData(String serialData) {
- this.serialData = serialData;
- }
-
- public Clob getClobData() {
- return clobData;
- }
-
- public void setClobData(Clob clobData) {
- this.clobData = clobData;
- }
-}
Modified: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/ClobTest.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/ClobTest.java 2006-11-18 04:21:05 UTC (rev 10846)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/ClobTest.java 2006-11-21 16:04:45 UTC (rev 10847)
@@ -5,11 +5,12 @@
import junit.framework.Test;
import junit.framework.TestSuite;
-import org.hibernate.test.TestCase;
+import org.hibernate.test.DatabaseSpecificTestCase;
import org.hibernate.Session;
import org.hibernate.Hibernate;
import org.hibernate.LockMode;
import org.hibernate.dialect.H2Dialect;
+import org.hibernate.dialect.Dialect;
/**
* Test various access scenarios for eager and lazy materialization
@@ -18,7 +19,7 @@
*
* @author Steve Ebersole
*/
-public class ClobTest extends TestCase {
+public class ClobTest extends DatabaseSpecificTestCase {
private static final int CLOB_SIZE = 10000;
public ClobTest(String name) {
@@ -26,69 +27,65 @@
}
protected String[] getMappings() {
- return new String[] { "lob/ClobHoldingEntity.hbm.xml" };
+ return new String[] { "lob/LobMappings.hbm.xml" };
}
public static Test suite() {
return new TestSuite( ClobTest.class );
}
- public void testBoundedMaterializedClobAccess() {
- if ( !supportsExpectedLobUsagePattern() ) {
- return;
- }
+ public boolean appliesTo(Dialect dialect) {
+ return supportsExpectedLobUsagePattern();
+ }
+ public void testBoundedMaterializedClobAccess() {
String original = buildRecursively( CLOB_SIZE, 'x' );
String changed = buildRecursively( CLOB_SIZE, 'y' );
Session s = openSession();
s.beginTransaction();
- ClobHoldingEntity entity = new ClobHoldingEntity();
- entity.setSerialData( original );
+ LobHolder entity = new LobHolder();
+ entity.setMaterializedClob( original );
s.save( entity );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
- entity = ( ClobHoldingEntity ) s.get( ClobHoldingEntity.class, entity.getId() );
- assertEquals( CLOB_SIZE, entity.getSerialData().length() );
- assertEquals( original, entity.getSerialData() );
- entity.setSerialData( changed );
+ entity = ( LobHolder ) s.get( LobHolder.class, entity.getId() );
+ assertEquals( CLOB_SIZE, entity.getMaterializedClob().length() );
+ assertEquals( original, entity.getMaterializedClob() );
+ entity.setMaterializedClob( changed );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
- entity = ( ClobHoldingEntity ) s.get( ClobHoldingEntity.class, entity.getId() );
- assertEquals( CLOB_SIZE, entity.getSerialData().length() );
- assertEquals( changed, entity.getSerialData() );
+ entity = ( LobHolder ) s.get( LobHolder.class, entity.getId() );
+ assertEquals( CLOB_SIZE, entity.getMaterializedClob().length() );
+ assertEquals( changed, entity.getMaterializedClob() );
s.delete( entity );
s.getTransaction().commit();
s.close();
}
public void testBoundedClobLocatorAccess() throws Throwable {
- if ( !supportsExpectedLobUsagePattern() ) {
- return;
- }
-
String original = buildRecursively( CLOB_SIZE, 'x' );
String changed = buildRecursively( CLOB_SIZE, 'y' );
Session s = openSession();
s.beginTransaction();
- ClobHoldingEntity entity = new ClobHoldingEntity();
- entity.setClobData( Hibernate.createClob( original ) );
+ LobHolder entity = new LobHolder();
+ entity.setClobLocator( Hibernate.createClob( original ) );
s.save( entity );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
- entity = ( ClobHoldingEntity ) s.get( ClobHoldingEntity.class, entity.getId() );
- assertEquals( CLOB_SIZE, entity.getClobData().length() );
- assertEquals( original, extractData( entity.getClobData() ) );
+ entity = ( LobHolder ) s.get( LobHolder.class, entity.getId() );
+ assertEquals( CLOB_SIZE, entity.getClobLocator().length() );
+ assertEquals( original, extractData( entity.getClobLocator() ) );
s.getTransaction().commit();
s.close();
@@ -96,20 +93,20 @@
if ( supportsLobValueChangePropogation() ) {
s = openSession();
s.beginTransaction();
- entity = ( ClobHoldingEntity ) s.get( ClobHoldingEntity.class, entity.getId(), LockMode.UPGRADE );
- entity.getClobData().truncate( 1 );
- entity.getClobData().setString( 1, changed );
+ entity = ( LobHolder ) s.get( LobHolder.class, entity.getId(), LockMode.UPGRADE );
+ entity.getClobLocator().truncate( 1 );
+ entity.getClobLocator().setString( 1, changed );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
- entity = ( ClobHoldingEntity ) s.get( ClobHoldingEntity.class, entity.getId(), LockMode.UPGRADE );
- assertNotNull( entity.getClobData() );
- assertEquals( CLOB_SIZE, entity.getClobData().length() );
- assertEquals( changed, extractData( entity.getClobData() ) );
- entity.getClobData().truncate( 1 );
- entity.getClobData().setString( 1, original );
+ entity = ( LobHolder ) s.get( LobHolder.class, entity.getId(), LockMode.UPGRADE );
+ assertNotNull( entity.getClobLocator() );
+ assertEquals( CLOB_SIZE, entity.getClobLocator().length() );
+ assertEquals( changed, extractData( entity.getClobLocator() ) );
+ entity.getClobLocator().truncate( 1 );
+ entity.getClobLocator().setString( 1, original );
s.getTransaction().commit();
s.close();
}
@@ -117,19 +114,19 @@
// test mutation via supplying a new clob locator instance...
s = openSession();
s.beginTransaction();
- entity = ( ClobHoldingEntity ) s.get( ClobHoldingEntity.class, entity.getId(), LockMode.UPGRADE );
- assertNotNull( entity.getClobData() );
- assertEquals( CLOB_SIZE, entity.getClobData().length() );
- assertEquals( original, extractData( entity.getClobData() ) );
- entity.setClobData( Hibernate.createClob( changed ) );
+ entity = ( LobHolder ) s.get( LobHolder.class, entity.getId(), LockMode.UPGRADE );
+ assertNotNull( entity.getClobLocator() );
+ assertEquals( CLOB_SIZE, entity.getClobLocator().length() );
+ assertEquals( original, extractData( entity.getClobLocator() ) );
+ entity.setClobLocator( Hibernate.createClob( changed ) );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
- entity = ( ClobHoldingEntity ) s.get( ClobHoldingEntity.class, entity.getId() );
- assertEquals( CLOB_SIZE, entity.getClobData().length() );
- assertEquals( changed, extractData( entity.getClobData() ) );
+ entity = ( LobHolder ) s.get( LobHolder.class, entity.getId() );
+ assertEquals( CLOB_SIZE, entity.getClobLocator().length() );
+ assertEquals( changed, extractData( entity.getClobLocator() ) );
s.delete( entity );
s.getTransaction().commit();
s.close();
@@ -137,7 +134,7 @@
}
public void testUnboundedClobLocatorAccess() throws Throwable {
- if ( !supportsExpectedLobUsagePattern() || ! supportsUnboundedLobLocatorMaterialization() ) {
+ if ( ! supportsUnboundedLobLocatorMaterialization() ) {
return;
}
@@ -149,8 +146,8 @@
Session s = openSession();
s.beginTransaction();
- ClobHoldingEntity entity = new ClobHoldingEntity();
- entity.setClobData( Hibernate.createClob( original ) );
+ LobHolder entity = new LobHolder();
+ entity.setClobLocator( Hibernate.createClob( original ) );
s.save( entity );
s.getTransaction().commit();
s.close();
@@ -159,12 +156,12 @@
// at that point it is unbounded...
s = openSession();
s.beginTransaction();
- entity = ( ClobHoldingEntity ) s.get( ClobHoldingEntity.class, entity.getId() );
+ entity = ( LobHolder ) s.get( LobHolder.class, entity.getId() );
s.getTransaction().commit();
s.close();
- assertEquals( CLOB_SIZE, entity.getClobData().length() );
- assertEquals( original, extractData( entity.getClobData() ) );
+ assertEquals( CLOB_SIZE, entity.getClobLocator().length() );
+ assertEquals( original, extractData( entity.getClobLocator() ) );
s = openSession();
s.beginTransaction();
Added: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/LobHolder.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/LobHolder.java 2006-11-18 04:21:05 UTC (rev 10846)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/LobHolder.java 2006-11-21 16:04:45 UTC (rev 10847)
@@ -0,0 +1,90 @@
+package org.hibernate.test.lob;
+
+import java.io.Serializable;
+import java.sql.Clob;
+import java.sql.Blob;
+
+/**
+ * An entity containing all kinds of good LOB-type data...
+ * <p/>
+ * {@link #serialData} is used to hold general serializable data which is
+ * mapped via the {@link org.hibernate.type.SerializableType}.
+ * <p/>
+ * {@link #materializedClob} is used to hold CLOB data that is materialized
+ * into a String immediately; it is mapped via the
+ * {@link org.hibernate.type.TextType}.
+ * <p/>
+ * {@link #clobLocator} is used to hold CLOB data that is materialized lazily
+ * via a JDBC CLOB locator; it is mapped via the
+ * {@link org.hibernate.type.ClobType}
+ * <p/>
+ * {@link #materializedBlob} is used to hold BLOB data that is materialized
+ * into a byte array immediately; it is mapped via the
+ * {@link org.hibernate.test.lob.MaterializedBlobType}.
+ * <p/>
+ * {@link #blobLocator} is used to hold BLOB data that is materialized lazily
+ * via a JDBC BLOB locator; it is mapped via the
+ * {@link org.hibernate.type.BlobType}
+ *
+ *
+ * @author Steve Ebersole
+ */
+public class LobHolder {
+ private Long id;
+
+ private Serializable serialData;
+
+ private String materializedClob;
+ private Clob clobLocator;
+
+ private byte[] materializedBlob;
+ private Blob blobLocator;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public Serializable getSerialData() {
+ return serialData;
+ }
+
+ public void setSerialData(Serializable serialData) {
+ this.serialData = serialData;
+ }
+
+ public String getMaterializedClob() {
+ return materializedClob;
+ }
+
+ public void setMaterializedClob(String materializedClob) {
+ this.materializedClob = materializedClob;
+ }
+
+ public Clob getClobLocator() {
+ return clobLocator;
+ }
+
+ public void setClobLocator(Clob clobLocator) {
+ this.clobLocator = clobLocator;
+ }
+
+ public byte[] getMaterializedBlob() {
+ return materializedBlob;
+ }
+
+ public void setMaterializedBlob(byte[] materializedBlob) {
+ this.materializedBlob = materializedBlob;
+ }
+
+ public Blob getBlobLocator() {
+ return blobLocator;
+ }
+
+ public void setBlobLocator(Blob blobLocator) {
+ this.blobLocator = blobLocator;
+ }
+}
Added: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/LobMappings.hbm.xml
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/LobMappings.hbm.xml 2006-11-18 04:21:05 UTC (rev 10846)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/LobMappings.hbm.xml 2006-11-21 16:04:45 UTC (rev 10847)
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+ "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
+ "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.lob">
+
+ <class name="LobHolder" table="LOB_ENTITY">
+ <id name="id" type="long" column="ID">
+ <generator class="increment"/>
+ </id>
+
+ <property name="serialData" column="SER_DATA" type="serializable"/>
+
+ <property name="materializedClob" column="MAT_CLOB_DATA" type="text"/>
+ <property name="clobLocator" column="CLOB_DATA" type="clob" />
+
+ <property name="materializedBlob" column="MAT_BLOB_DATA" type="org.hibernate.test.lob.MaterializedBlobType"/>
+ <property name="blobLocator" column="BLOB_DATA" type="blob" />
+ </class>
+
+</hibernate-mapping>
\ No newline at end of file
Added: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/LobSuite.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/LobSuite.java 2006-11-18 04:21:05 UTC (rev 10846)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/LobSuite.java 2006-11-21 16:04:45 UTC (rev 10847)
@@ -0,0 +1,19 @@
+package org.hibernate.test.lob;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class LobSuite {
+ public static Test suite() {
+ TestSuite suite = new TestSuite( "LOB handling tests" );
+ suite.addTest( SerializableTypeTest.suite() );
+ suite.addTest( BlobTest.suite() );
+ suite.addTest( ClobTest.suite() );
+ return suite;
+ }
+}
Deleted: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/LobTest.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/LobTest.java 2006-11-18 04:21:05 UTC (rev 10846)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/LobTest.java 2006-11-21 16:04:45 UTC (rev 10847)
@@ -1,73 +0,0 @@
-// $Id$
-package org.hibernate.test.lob;
-
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
-import org.hibernate.Session;
-import org.hibernate.Transaction;
-import org.hibernate.test.TestCase;
-
-/**
- * Implementation of DynamicFilterTest.
- *
- * @author Steve
- */
-public class LobTest extends TestCase {
-
- public LobTest(String testName) {
- super(testName);
- }
-
- public void testNewSerializableType() {
- Session session = openSession();
- Transaction txn = session.beginTransaction();
-
- User user = new User();
- user.setEmail("nobody(a)nowhere.com");
- user.setName(new Name());
- user.getName().setFirstName("John");
- user.getName().setInitial(new Character('Q'));
- user.getName().setLastName("Public");
- user.setPassword("password");
- user.setHandle("myHandle");
-
- String payloadText = "Initial payload";
- user.setSerialData( new SerializableData(payloadText) );
-
- session.save(user);
- txn.commit();
-
- session.close();
- user = null;
-
- session = openSession();
- user = (User) session.createQuery("select u from User as u where u.handle = :myHandle")
- .setString("myHandle", "myHandle")
- .uniqueResult();
-
- SerializableData serialData = (SerializableData) user.getSerialData();
- assertTrue(payloadText.equals(serialData.getPayload()));
- session.close();
- }
-
- /**
- * Define the mappings needed for these tests.
- *
- * @return Mappings for these tests.
- */
- protected String[] getMappings() {
- return new String[] {
- "lob/User.hbm.xml"
- };
- }
-
- public String getCacheConcurrencyStrategy() {
- return null;
- }
-
- public static Test suite() {
- return new TestSuite(LobTest.class);
- }
-
-}
Added: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/MaterializedBlobType.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/MaterializedBlobType.java 2006-11-18 04:21:05 UTC (rev 10846)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/MaterializedBlobType.java 2006-11-21 16:04:45 UTC (rev 10847)
@@ -0,0 +1,33 @@
+package org.hibernate.test.lob;
+
+import java.sql.Types;
+
+import org.hibernate.type.AbstractBynaryType;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class MaterializedBlobType extends AbstractBynaryType {
+
+ public int sqlType() {
+ return Types.BLOB;
+ }
+
+ public String getName() {
+ return "materialized-blob";
+ }
+
+ public Class getReturnedClass() {
+ return byte[].class;
+ }
+
+ protected Object toExternalFormat(byte[] bytes) {
+ return bytes;
+ }
+
+ protected byte[] toInternalFormat(Object bytes) {
+ return ( byte[] ) bytes;
+ }
+}
Deleted: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/Name.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/Name.java 2006-11-18 04:21:05 UTC (rev 10846)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/Name.java 2006-11-21 16:04:45 UTC (rev 10847)
@@ -1,58 +0,0 @@
-// $Id$
-package org.hibernate.test.lob;
-
-import java.io.Serializable;
-
-/**
- * Implementation of Name.
- *
- * @author Steve
- */
-public class Name implements Serializable {
-
- private String firstName;
- private String lastName;
- private Character initial;
-
- public Name() {}
-
- public Name(String first, Character middle, String last) {
- firstName = first;
- initial = middle;
- lastName = last;
- }
-
- public String getFirstName() {
- return firstName;
- }
-
- public void setFirstName(String firstName) {
- this.firstName = firstName;
- }
-
- public Character getInitial() {
- return initial;
- }
-
- public void setInitial(Character initial) {
- this.initial = initial;
- }
-
- public String getLastName() {
- return lastName;
- }
-
- public void setLastName(String lastName) {
- this.lastName = lastName;
- }
-
- public String toString() {
- StringBuffer buf = new StringBuffer()
- .append(firstName)
- .append(' ');
- if (initial!=null) buf.append(initial)
- .append(' ');
- return buf.append(lastName)
- .toString();
- }
-}
Copied: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/SerializableTypeTest.java (from rev 10805, branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/LobTest.java)
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/LobTest.java 2006-11-14 13:07:51 UTC (rev 10805)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/SerializableTypeTest.java 2006-11-21 16:04:45 UTC (rev 10847)
@@ -0,0 +1,55 @@
+// $Id$
+package org.hibernate.test.lob;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.Session;
+import org.hibernate.test.TestCase;
+
+/**
+ * Tests of {@link org.hibernate.type.SerializableType}
+ *
+ * @author Steve Ebersole
+ */
+public class SerializableTypeTest extends TestCase {
+
+ public SerializableTypeTest(String testName) {
+ super( testName );
+ }
+
+ public static Test suite() {
+ return new TestSuite( SerializableTypeTest.class );
+ }
+
+ protected String[] getMappings() {
+ return new String[] { "lob/LobMappings.hbm.xml" };
+ }
+
+ public String getCacheConcurrencyStrategy() {
+ return null;
+ }
+
+ public void testNewSerializableType() {
+ final String payloadText = "Initial payload";
+
+ Session s = openSession();
+ s.beginTransaction();
+ LobHolder holder = new LobHolder();
+ holder.setSerialData( new SerializableData( payloadText ) );
+ s.save( holder );
+ s.getTransaction().commit();
+ s.close();
+
+ s = openSession();
+ s.beginTransaction();
+ holder = ( LobHolder ) s.get( LobHolder.class, holder.getId() );
+ SerializableData serialData = ( SerializableData ) holder.getSerialData();
+ assertEquals( payloadText, serialData.getPayload() );
+ s.delete( holder );
+ s.getTransaction().commit();
+ s.close();
+ }
+
+
+}
Property changes on: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/SerializableTypeTest.java
___________________________________________________________________
Name: svn:keywords
+ Author Date Id Revision
Name: svn:eol-style
+ native
Deleted: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/User.hbm.xml
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/User.hbm.xml 2006-11-18 04:21:05 UTC (rev 10846)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/User.hbm.xml 2006-11-21 16:04:45 UTC (rev 10847)
@@ -1,34 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE hibernate-mapping PUBLIC
- "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
-
-<hibernate-mapping package="org.hibernate.test.lob">
-
- <class name="User" table="users">
-
- <id name="id" type="long" unsaved-value="null">
- <generator class="increment"/>
- </id>
-
- <!-- We don't change the handle, so map it with update="false". -->
- <property name="handle" unique="true" not-null="true" update="false"/>
-
- <!-- password is a keyword in some databases, so quote it -->
- <property name="password" column="`password`" not-null="true"/>
-
- <property name="email"/>
-
- <property name="serialData" column="ser_data" type="serializable"/>
-
- <!-- Mapping for the component class Name -->
- <component name="name">
- <property name="firstName"/>
- <!-- initial is a keyword in some databases, so quote it -->
- <property name="initial" column="`initial`"/>
- <property name="lastName"/>
- </component>
-
- </class>
-
-</hibernate-mapping>
\ No newline at end of file
Deleted: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/User.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/User.java 2006-11-18 04:21:05 UTC (rev 10846)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/lob/User.java 2006-11-21 16:04:45 UTC (rev 10847)
@@ -1,79 +0,0 @@
-// $Id$
-package org.hibernate.test.lob;
-
-import java.io.Serializable;
-
-/**
- * Implementation of User.
- *
- * @author Steve
- */
-public class User implements Serializable {
- private Long id;
- private String handle;
- private String password;
- private Name name;
- private String email;
- private Serializable serialData;
-
- public String getHandle() {
- return handle;
- }
-
- public void setHandle(String handle) {
- this.handle = handle;
- }
-
- public Long getId() {
- return id;
- }
-
- protected void setId(Long id) {
- this.id = id;
- }
-
- public Name getName() {
- return name;
- }
-
- public void setName(Name name) {
- this.name = name;
- }
-
- public String getPassword() {
- return password;
- }
-
- public void setPassword(String password) {
- this.password = password;
- }
-
- public String getEmail() {
- return email;
- }
-
- public void setEmail(String email) {
- this.email = email;
- }
-
- public boolean equals(Object other) {
- if (other==null) return false;
- if ( !(other instanceof User) ) return false;
- return ( (User) other ).getHandle().equals(handle);
- }
-
- public int hashCode() {
- return handle.hashCode();
- }
-
-
- public Serializable getSerialData()
- {
- return serialData;
- }
-
- public void setSerialData(Serializable serialData)
- {
- this.serialData = serialData;
- }
-}
18 years, 1 month
Hibernate SVN: r10846 - in branches/Branch_3_2/Hibernate3: src/org/hibernate src/org/hibernate/impl test/org/hibernate/test/sql
by hibernate-commits@lists.jboss.org
Author: steve.ebersole(a)jboss.com
Date: 2006-11-17 23:21:05 -0500 (Fri, 17 Nov 2006)
New Revision: 10846
Modified:
branches/Branch_3_2/Hibernate3/src/org/hibernate/SQLQuery.java
branches/Branch_3_2/Hibernate3/src/org/hibernate/impl/SQLQueryImpl.java
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/sql/GeneralTest.java
Log:
HHH-2130 : SQLQuery + query space synchronization
Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/SQLQuery.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/SQLQuery.java 2006-11-18 04:20:30 UTC (rev 10845)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/SQLQuery.java 2006-11-18 04:21:05 UTC (rev 10846)
@@ -60,4 +60,34 @@
* Use a predefined named ResultSetMapping
*/
public SQLQuery setResultSetMapping(String name);
+
+ /**
+ * Adds a query space for auto-flush synchronization.
+ *
+ * @param querySpace The query space to be auto-flushed for this query.
+ * @return this, for method chaning
+ */
+ public SQLQuery addSynchronizedQuerySpace(String querySpace);
+
+ /**
+ * Adds an entity name or auto-flush synchronization.
+ *
+ * @param entityName The name of the entity upon whose defined
+ * query spaces we should additionally synchronize.
+ * @return this, for method chaning
+ * @throws MappingException Indicates the given entity name could not be
+ * resolved.
+ */
+ public SQLQuery addSynchronizedEntityName(String entityName) throws MappingException;
+
+ /**
+ * Adds an entity name or auto-flush synchronization.
+ *
+ * @param entityClass The class of the entity upon whose defined
+ * query spaces we should additionally synchronize.
+ * @return this, for method chaning
+ * @throws MappingException Indicates the given entity class could not be
+ * resolved.
+ */
+ public SQLQuery addSynchronizedEntityClass(Class entityClass) throws MappingException;
}
Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/impl/SQLQueryImpl.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/impl/SQLQueryImpl.java 2006-11-18 04:20:30 UTC (rev 10845)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/impl/SQLQueryImpl.java 2006-11-18 04:21:05 UTC (rev 10846)
@@ -7,6 +7,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.io.Serializable;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
@@ -47,7 +48,7 @@
public class SQLQueryImpl extends AbstractQueryImpl implements SQLQuery {
private final List queryReturns;
- private final Collection querySpaces;
+ private Collection querySpaces;
private final boolean callable;
private boolean autodiscovertypes;
@@ -56,6 +57,7 @@
*
* @param queryDef The representation of the defined <sql-query/>.
* @param session The session to which this SQLQueryImpl belongs.
+ * @param parameterMetadata Metadata about parameters found in the query.
*/
SQLQueryImpl(NamedSQLQueryDefinition queryDef, SessionImplementor session, ParameterMetadata parameterMetadata) {
super( queryDef.getQueryString(), queryDef.getFlushMode(), session, parameterMetadata );
@@ -296,7 +298,35 @@
}
return this;
}
-
+
+ public SQLQuery addSynchronizedQuerySpace(String querySpace) {
+ if ( querySpaces == null ) {
+ querySpaces = new ArrayList();
+ }
+ querySpaces.add( querySpace );
+ return this;
+ }
+
+ public SQLQuery addSynchronizedEntityName(String entityName) {
+ return addQuerySpaces( getSession().getFactory().getEntityPersister( entityName ).getQuerySpaces() );
+ }
+
+ public SQLQuery addSynchronizedEntityClass(Class entityClass) {
+ return addQuerySpaces( getSession().getFactory().getEntityPersister( entityClass.getName() ).getQuerySpaces() );
+ }
+
+ private SQLQuery addQuerySpaces(Serializable[] spaces) {
+ if ( spaces != null ) {
+ if ( querySpaces == null ) {
+ querySpaces = new ArrayList();
+ }
+ for ( int i = 0; i < spaces.length; i++ ) {
+ querySpaces.add( spaces[i] );
+ }
+ }
+ return this;
+ }
+
public int executeUpdate() throws HibernateException {
Map namedParams = getNamedParams();
return getSession().executeNativeUpdate(generateQuerySpecification( namedParams ), getQueryParameters( namedParams ));
Modified: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/sql/GeneralTest.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/sql/GeneralTest.java 2006-11-18 04:20:30 UTC (rev 10845)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/sql/GeneralTest.java 2006-11-18 04:21:05 UTC (rev 10846)
@@ -15,6 +15,8 @@
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
import org.hibernate.test.TestCase;
import org.hibernate.transform.DistinctRootEntityResultTransformer;
import org.hibernate.transform.Transformers;
@@ -28,6 +30,19 @@
super( x );
}
+ public static Test suite() {
+ return new TestSuite(GeneralTest.class);
+ }
+
+ protected String[] getMappings() {
+ return new String[] { "sql/General.hbm.xml" };
+ }
+
+ protected void configure(Configuration cfg) {
+ super.configure( cfg );
+ cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
+ }
+
protected String getOrganizationFetchJoinEmploymentSQL() {
return "SELECT org.ORGID as {org.id}, " +
" org.NAME as {org.name}, " +
@@ -67,11 +82,6 @@
" join PERSON pers on pers.PERID = emp.EMPLOYEE ";
}
-
- protected String[] getMappings() {
- return new String[] { "sql/General.hbm.xml" };
- }
-
public void testFailOnNoAddEntityOrScalar() {
// Note: this passes, but for the wrong reason.
// there is actually an exception thrown, but it is the database
@@ -92,6 +102,30 @@
}
}
+ public void testManualSynchronization() {
+ Session s = openSession();
+ s.beginTransaction();
+
+ sfi().getStatistics().clear();
+
+ // create an Organization...
+ Organization jboss = new Organization( "JBoss" );
+ s.persist( jboss );
+
+ // now query on Employment, this should not cause an auto-flush
+ s.createSQLQuery( getEmploymentSQL() ).list();
+ assertEquals( 0, sfi().getStatistics().getEntityInsertCount() );
+
+ // now try to query on Employment but this time add Organization as a synchronized query space...
+ s.createSQLQuery( getEmploymentSQL() ).addSynchronizedEntityClass( Organization.class ).list();
+ assertEquals( 1, sfi().getStatistics().getEntityInsertCount() );
+
+ // clean up
+ s.delete( jboss );
+ s.getTransaction().commit();
+ s.close();
+ }
+
public void testSQLQueryInterface() {
Session s = openSession();
Transaction t = s.beginTransaction();
@@ -372,7 +406,7 @@
" {prod_orders}.orgid as orgid3_1_,\r\n" +
" {prod_orders}.ordernumber as ordernum2_3_1_,\r\n" +
" product.name as {product.name}," +
- " {prod_orders.element.*}," +
+ " {prod_orders.element.*}" +
/*" orders.PROD_NO as PROD4_3_1_,\r\n" +
" orders.person as person3_1_,\r\n" +
" orders.PROD_ORGID as PROD3_0__,\r\n" +
@@ -561,8 +595,4 @@
}
}
- public static Test suite() {
- return new TestSuite(GeneralTest.class);
- }
-
}
18 years, 1 month
Hibernate SVN: r10845 - in trunk/Hibernate3: src/org/hibernate src/org/hibernate/impl test/org/hibernate/test/sql
by hibernate-commits@lists.jboss.org
Author: steve.ebersole(a)jboss.com
Date: 2006-11-17 23:20:30 -0500 (Fri, 17 Nov 2006)
New Revision: 10845
Modified:
trunk/Hibernate3/src/org/hibernate/SQLQuery.java
trunk/Hibernate3/src/org/hibernate/impl/SQLQueryImpl.java
trunk/Hibernate3/test/org/hibernate/test/sql/GeneralTest.java
Log:
HHH-2130 : SQLQuery + query space synchronization
Modified: trunk/Hibernate3/src/org/hibernate/SQLQuery.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/SQLQuery.java 2006-11-17 22:15:26 UTC (rev 10844)
+++ trunk/Hibernate3/src/org/hibernate/SQLQuery.java 2006-11-18 04:20:30 UTC (rev 10845)
@@ -60,4 +60,34 @@
* Use a predefined named ResultSetMapping
*/
public SQLQuery setResultSetMapping(String name);
+
+ /**
+ * Adds a query space for auto-flush synchronization.
+ *
+ * @param querySpace The query space to be auto-flushed for this query.
+ * @return this, for method chaning
+ */
+ public SQLQuery addSynchronizedQuerySpace(String querySpace);
+
+ /**
+ * Adds an entity name or auto-flush synchronization.
+ *
+ * @param entityName The name of the entity upon whose defined
+ * query spaces we should additionally synchronize.
+ * @return this, for method chaning
+ * @throws MappingException Indicates the given entity name could not be
+ * resolved.
+ */
+ public SQLQuery addSynchronizedEntityName(String entityName) throws MappingException;
+
+ /**
+ * Adds an entity name or auto-flush synchronization.
+ *
+ * @param entityClass The class of the entity upon whose defined
+ * query spaces we should additionally synchronize.
+ * @return this, for method chaning
+ * @throws MappingException Indicates the given entity class could not be
+ * resolved.
+ */
+ public SQLQuery addSynchronizedEntityClass(Class entityClass) throws MappingException;
}
Modified: trunk/Hibernate3/src/org/hibernate/impl/SQLQueryImpl.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/impl/SQLQueryImpl.java 2006-11-17 22:15:26 UTC (rev 10844)
+++ trunk/Hibernate3/src/org/hibernate/impl/SQLQueryImpl.java 2006-11-18 04:20:30 UTC (rev 10845)
@@ -7,6 +7,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.io.Serializable;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
@@ -47,7 +48,7 @@
public class SQLQueryImpl extends AbstractQueryImpl implements SQLQuery {
private final List queryReturns;
- private final Collection querySpaces;
+ private Collection querySpaces;
private final boolean callable;
private boolean autodiscovertypes;
@@ -56,6 +57,7 @@
*
* @param queryDef The representation of the defined <sql-query/>.
* @param session The session to which this SQLQueryImpl belongs.
+ * @param parameterMetadata Metadata about parameters found in the query.
*/
SQLQueryImpl(NamedSQLQueryDefinition queryDef, SessionImplementor session, ParameterMetadata parameterMetadata) {
super( queryDef.getQueryString(), queryDef.getFlushMode(), session, parameterMetadata );
@@ -65,7 +67,7 @@
if (definition == null) {
throw new MappingException(
"Unable to find resultset-ref definition: " +
- queryDef.getResultSetRef()
+ queryDef.getResultSetRef()
);
}
this.queryReturns = Arrays.asList( definition.getQueryReturns() );
@@ -125,16 +127,16 @@
ParameterMetadata parameterMetadata) {
this( sql, returnAliases, returnClasses, null, session, null, null, parameterMetadata );
}
-
+
SQLQueryImpl(String sql, SessionImplementor session, ParameterMetadata parameterMetadata) {
super( sql, null, session, parameterMetadata );
queryReturns = new ArrayList();
querySpaces = null;
callable = false;
}
-
+
private static final NativeSQLQueryReturn[] NO_SQL_RETURNS = new NativeSQLQueryReturn[0];
-
+
private NativeSQLQueryReturn[] getQueryReturns() {
return ( NativeSQLQueryReturn[] ) queryReturns.toArray( NO_SQL_RETURNS );
}
@@ -223,11 +225,11 @@
public Type[] getReturnTypes() throws HibernateException {
throw new UnsupportedOperationException("not yet implemented for SQL queries");
}
-
+
public Query setLockMode(String alias, LockMode lockMode) {
throw new UnsupportedOperationException("cannot set the lock mode for a native SQL query");
}
-
+
protected Map getLockModes() {
//we never need to apply locks to the SQL
return CollectionHelper.EMPTY_MAP;
@@ -263,7 +265,7 @@
public SQLQuery addEntity(String alias, Class entityClass) {
return addEntity( alias, entityClass.getName() );
}
-
+
public SQLQuery addJoin(String alias, String path, LockMode lockMode) {
int loc = path.indexOf('.');
if ( loc < 0 ) {
@@ -296,7 +298,35 @@
}
return this;
}
-
+
+ public SQLQuery addSynchronizedQuerySpace(String querySpace) {
+ if ( querySpaces == null ) {
+ querySpaces = new ArrayList();
+ }
+ querySpaces.add( querySpace );
+ return this;
+ }
+
+ public SQLQuery addSynchronizedEntityName(String entityName) {
+ return addQuerySpaces( getSession().getFactory().getEntityPersister( entityName ).getQuerySpaces() );
+ }
+
+ public SQLQuery addSynchronizedEntityClass(Class entityClass) {
+ return addQuerySpaces( getSession().getFactory().getEntityPersister( entityClass.getName() ).getQuerySpaces() );
+ }
+
+ private SQLQuery addQuerySpaces(Serializable[] spaces) {
+ if ( spaces != null ) {
+ if ( querySpaces == null ) {
+ querySpaces = new ArrayList();
+ }
+ for ( int i = 0; i < spaces.length; i++ ) {
+ querySpaces.add( spaces[i] );
+ }
+ }
+ return this;
+ }
+
public int executeUpdate() throws HibernateException {
Map namedParams = getNamedParams();
return getSession().executeNativeUpdate(generateQuerySpecification( namedParams ), getQueryParameters( namedParams ));
Modified: trunk/Hibernate3/test/org/hibernate/test/sql/GeneralTest.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/sql/GeneralTest.java 2006-11-17 22:15:26 UTC (rev 10844)
+++ trunk/Hibernate3/test/org/hibernate/test/sql/GeneralTest.java 2006-11-18 04:20:30 UTC (rev 10845)
@@ -15,6 +15,8 @@
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
import org.hibernate.test.TestCase;
import org.hibernate.transform.DistinctRootEntityResultTransformer;
import org.hibernate.transform.Transformers;
@@ -28,6 +30,19 @@
super( x );
}
+ public static Test suite() {
+ return new TestSuite(GeneralTest.class);
+ }
+
+ protected String[] getMappings() {
+ return new String[] { "sql/General.hbm.xml" };
+ }
+
+ protected void configure(Configuration cfg) {
+ super.configure( cfg );
+ cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
+ }
+
protected String getOrganizationFetchJoinEmploymentSQL() {
return "SELECT org.ORGID as {org.id}, " +
" org.NAME as {org.name}, " +
@@ -67,11 +82,6 @@
" join PERSON pers on pers.PERID = emp.EMPLOYEE ";
}
-
- protected String[] getMappings() {
- return new String[] { "sql/General.hbm.xml" };
- }
-
public void testFailOnNoAddEntityOrScalar() {
// Note: this passes, but for the wrong reason.
// there is actually an exception thrown, but it is the database
@@ -92,6 +102,30 @@
}
}
+ public void testManualSynchronization() {
+ Session s = openSession();
+ s.beginTransaction();
+
+ sfi().getStatistics().clear();
+
+ // create an Organization...
+ Organization jboss = new Organization( "JBoss" );
+ s.persist( jboss );
+
+ // now query on Employment, this should not cause an auto-flush
+ s.createSQLQuery( getEmploymentSQL() ).list();
+ assertEquals( 0, sfi().getStatistics().getEntityInsertCount() );
+
+ // now try to query on Employment but this time add Organization as a synchronized query space...
+ s.createSQLQuery( getEmploymentSQL() ).addSynchronizedEntityClass( Organization.class ).list();
+ assertEquals( 1, sfi().getStatistics().getEntityInsertCount() );
+
+ // clean up
+ s.delete( jboss );
+ s.getTransaction().commit();
+ s.close();
+ }
+
public void testSQLQueryInterface() {
Session s = openSession();
Transaction t = s.beginTransaction();
@@ -372,7 +406,7 @@
" {prod_orders}.orgid as orgid3_1_,\r\n" +
" {prod_orders}.ordernumber as ordernum2_3_1_,\r\n" +
" product.name as {product.name}," +
- " {prod_orders.element.*}," +
+ " {prod_orders.element.*}" +
/*" orders.PROD_NO as PROD4_3_1_,\r\n" +
" orders.person as person3_1_,\r\n" +
" orders.PROD_ORGID as PROD3_0__,\r\n" +
@@ -399,14 +433,14 @@
public void testAutoDetectAliasing() {
Session s = openSession();
Transaction t = s.beginTransaction();
- Organization ifa = new Organization( "IFA" );
- Organization jboss = new Organization( "JBoss" );
- Person gavin = new Person( "Gavin" );
- Employment emp = new Employment( gavin, jboss, "AU" );
- Serializable orgId = s.save( jboss );
- Serializable orgId2 = s.save( ifa );
- s.save( gavin );
- s.save( emp );
+ Organization ifa = new Organization("IFA");
+ Organization jboss = new Organization("JBoss");
+ Person gavin = new Person("Gavin");
+ Employment emp = new Employment(gavin, jboss, "AU");
+ Serializable orgId = s.save(jboss);
+ Serializable orgId2 = s.save(ifa);
+ s.save(gavin);
+ s.save(emp);
t.commit();
s.close();
@@ -415,53 +449,50 @@
List list = s.createSQLQuery( getEmploymentSQL() )
.addEntity( Employment.class.getName() )
.list();
- assertEquals( 1, list.size() );
+ assertEquals( 1,list.size() );
- Employment emp2 = ( Employment ) list.get( 0 );
- assertEquals( emp2.getEmploymentId(), emp.getEmploymentId() );
- assertEquals( emp2.getStartDate().getDate(), emp.getStartDate().getDate() );
- assertEquals( emp2.getEndDate(), emp.getEndDate() );
+ Employment emp2 = (Employment) list.get(0);
+ assertEquals(emp2.getEmploymentId(), emp.getEmploymentId() );
+ assertEquals(emp2.getStartDate().getDate(), emp.getStartDate().getDate() );
+ assertEquals(emp2.getEndDate(), emp.getEndDate() );
s.clear();
list = s.createSQLQuery( getEmploymentSQL() )
- .addEntity( Employment.class.getName() )
- .setResultTransformer( Transformers.ALIAS_TO_ENTITY_MAP )
- .list();
- assertEquals( 1, list.size() );
- Map m = ( Map ) list.get( 0 );
- assertTrue( m.containsKey( "Employment" ) );
- assertEquals( 1, m.size() );
+ .addEntity( Employment.class.getName() )
+ .setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP)
+ .list();
+ assertEquals( 1,list.size() );
+ Map m = (Map) list.get(0);
+ assertTrue(m.containsKey("Employment"));
+ assertEquals(1,m.size());
- list = s.createSQLQuery( getEmploymentSQL() ).list();
- assertEquals( 1, list.size() );
- Object[] o = ( Object[] ) list.get( 0 );
- assertEquals( 8, o.length );
+ list = s.createSQLQuery(getEmploymentSQL()).list();
+ assertEquals(1, list.size());
+ Object[] o = (Object[]) list.get(0);
+ assertEquals(8, o.length);
- list = s.createSQLQuery( getEmploymentSQL() ).setResultTransformer( Transformers.ALIAS_TO_ENTITY_MAP ).list();
- assertEquals( 1, list.size() );
- m = ( Map ) list.get( 0 );
- assertTrue( m.containsKey( "EMPID" ) );
- assertTrue( m.containsKey( "VALUE" ) );
- assertTrue( m.containsKey( "ENDDATE" ) );
- assertEquals( 8, m.size() );
+ list = s.createSQLQuery(getEmploymentSQL()).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list();
+ assertEquals(1, list.size());
+ m = (Map) list.get(0);
+ assertTrue(m.containsKey("EMPID"));
+ assertTrue(m.containsKey("VALUE"));
+ assertTrue(m.containsKey("ENDDATE"));
+ assertEquals(8, m.size());
- list =
- s.createSQLQuery( getEmploymentSQLMixedScalarEntity() )
- .addScalar( "employerid" )
- .addEntity( Employment.class )
- .list();
- assertEquals( 1, list.size() );
- o = ( Object[] ) list.get( 0 );
- assertEquals( 2, o.length );
- assertClassAssignability( o[0].getClass(), Number.class );
- assertClassAssignability( o[1].getClass(), Employment.class );
+ list = s.createSQLQuery( getEmploymentSQLMixedScalarEntity() ).addScalar( "employerid" ).addEntity( Employment.class ).list();
+ assertEquals(1, list.size());
+ o = (Object[]) list.get(0);
+ assertEquals(2, o.length);
+ assertClassAssignability( o[0].getClass(), Number.class);
+ assertClassAssignability( o[1].getClass(), Employment.class);
- Query queryWithCollection = s.getNamedQuery( "organizationEmploymentsExplicitAliases" );
- queryWithCollection.setLong( "id", jboss.getId() );
+
+ Query queryWithCollection = s.getNamedQuery("organizationEmploymentsExplicitAliases");
+ queryWithCollection.setLong("id", jboss.getId() );
list = queryWithCollection.list();
- assertEquals( list.size(), 1 );
+ assertEquals(list.size(),1);
s.clear();
@@ -469,7 +500,7 @@
.addEntity( "org", Organization.class )
.addJoin( "emp", "org.employments" )
.list();
- assertEquals( 2, list.size() );
+ assertEquals( 2,list.size() );
s.clear();
@@ -477,30 +508,30 @@
.addEntity( "org", Organization.class )
.addJoin( "emp", "org.employments" )
.list();
- assertEquals( 2, list.size() );
+ assertEquals( 2,list.size() );
s.clear();
// TODO : why twice?
s.getNamedQuery( "organizationreturnproperty" ).list();
list = s.getNamedQuery( "organizationreturnproperty" ).list();
- assertEquals( 2, list.size() );
+ assertEquals( 2,list.size() );
s.clear();
list = s.getNamedQuery( "organizationautodetect" ).list();
- assertEquals( 2, list.size() );
+ assertEquals( 2,list.size() );
t.commit();
s.close();
s = openSession();
t = s.beginTransaction();
- s.delete( emp2 );
+ s.delete(emp2);
- s.delete( jboss );
- s.delete( gavin );
- s.delete( ifa );
+ s.delete(jboss);
+ s.delete(gavin);
+ s.delete(ifa);
t.commit();
s.close();
@@ -508,9 +539,7 @@
t = s.beginTransaction();
Dimension dim = new Dimension( 3, Integer.MAX_VALUE );
s.save( dim );
- list =
- s.createSQLQuery( "select d_len * d_width as surface, d_len * d_width * 10 as volume from Dimension" )
- .list();
+ list = s.createSQLQuery( "select d_len * d_width as surface, d_len * d_width * 10 as volume from Dimension" ).list();
s.delete( dim );
t.commit();
s.close();
@@ -521,17 +550,18 @@
enterprise.setModel( "USS" );
enterprise.setName( "Entreprise" );
enterprise.setSpeed( 50d );
- Dimension d = new Dimension( 45, 10 );
+ Dimension d = new Dimension(45, 10);
enterprise.setDimensions( d );
s.save( enterprise );
- Object[] result = ( Object[] ) s.getNamedQuery( "spaceship" ).uniqueResult();
- enterprise = ( SpaceShip ) result[0];
- assertTrue( 50d == enterprise.getSpeed() );
+ Object[] result = (Object[]) s.getNamedQuery( "spaceship" ).uniqueResult();
+ enterprise = (SpaceShip) result[0];
+ assertTrue(50d == enterprise.getSpeed() );
assertTrue( 450d == extractDoubleValue( result[1] ) );
assertTrue( 4500d == extractDoubleValue( result[2] ) );
s.delete( enterprise );
t.commit();
s.close();
+
}
public void testMixAndMatchEntityScalar() {
@@ -565,8 +595,4 @@
}
}
- public static Test suite() {
- return new TestSuite(GeneralTest.class);
- }
-
}
18 years, 1 month
Hibernate SVN: r10844 - in trunk/Hibernate3/src/org/hibernate: cfg impl
by hibernate-commits@lists.jboss.org
Author: steve.ebersole(a)jboss.com
Date: 2006-11-17 17:15:26 -0500 (Fri, 17 Nov 2006)
New Revision: 10844
Modified:
trunk/Hibernate3/src/org/hibernate/cfg/Environment.java
trunk/Hibernate3/src/org/hibernate/cfg/Settings.java
trunk/Hibernate3/src/org/hibernate/cfg/SettingsFactory.java
trunk/Hibernate3/src/org/hibernate/impl/SessionFactoryImpl.java
Log:
HHH-2193 : flag to control named query checking
Modified: trunk/Hibernate3/src/org/hibernate/cfg/Environment.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/cfg/Environment.java 2006-11-17 22:15:05 UTC (rev 10843)
+++ trunk/Hibernate3/src/org/hibernate/cfg/Environment.java 2006-11-17 22:15:26 UTC (rev 10844)
@@ -414,12 +414,21 @@
* The classname of the HQL query parser factory
*/
public static final String QUERY_TRANSLATOR = "hibernate.query.factory_class";
+
/**
* A comma-seperated list of token substitutions to use when translating a Hibernate
* query to SQL
*/
public static final String QUERY_SUBSTITUTIONS = "hibernate.query.substitutions";
+
/**
+ * Should named queries be checked during startup (the default is enabled).
+ * <p/>
+ * Mainly intended for test environments.
+ */
+ public static final String QUERY_STARTUP_CHECKING = "hibernate.query.startup_check";
+
+ /**
* Auto export/update schema using hbm2ddl tool. Valid values are <tt>update</tt>,
* <tt>create</tt>, <tt>create-drop</tt> and <tt>validate</tt>.
*/
Modified: trunk/Hibernate3/src/org/hibernate/cfg/Settings.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/cfg/Settings.java 2006-11-17 22:15:05 UTC (rev 10843)
+++ trunk/Hibernate3/src/org/hibernate/cfg/Settings.java 2006-11-17 22:15:26 UTC (rev 10844)
@@ -65,6 +65,7 @@
private boolean dataDefinitionImplicitCommit;
private boolean dataDefinitionInTransactionSupported;
private boolean strictJPAQLCompliance;
+ private boolean namedQueryStartupCheckingEnabled;
// private BytecodeProvider bytecodeProvider;
/**
@@ -247,7 +248,11 @@
return strictJPAQLCompliance;
}
+ public boolean isNamedQueryStartupCheckingEnabled() {
+ return namedQueryStartupCheckingEnabled;
+ }
+
// package protected setters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void setDefaultSchemaName(String string) {
@@ -422,6 +427,9 @@
this.strictJPAQLCompliance = strictJPAQLCompliance;
}
+ void setNamedQueryStartupCheckingEnabled(boolean namedQueryStartupCheckingEnabled) {
+ this.namedQueryStartupCheckingEnabled = namedQueryStartupCheckingEnabled;
+ }
// public BytecodeProvider getBytecodeProvider() {
Modified: trunk/Hibernate3/src/org/hibernate/cfg/SettingsFactory.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/cfg/SettingsFactory.java 2006-11-17 22:15:05 UTC (rev 10843)
+++ trunk/Hibernate3/src/org/hibernate/cfg/SettingsFactory.java 2006-11-17 22:15:26 UTC (rev 10844)
@@ -296,6 +296,10 @@
log.info( "Default entity-mode: " + defaultEntityMode );
settings.setDefaultEntityMode( defaultEntityMode );
+ boolean namedQueryChecking = PropertiesHelper.getBoolean( Environment.QUERY_STARTUP_CHECKING, properties, true );
+ log.info( "Named query checking : " + enabledDisabled( namedQueryChecking ) );
+ settings.setNamedQueryStartupCheckingEnabled( namedQueryChecking );
+
// String provider = properties.getProperty( Environment.BYTECODE_PROVIDER );
// log.info( "Bytecode provider name : " + provider );
// BytecodeProvider bytecodeProvider = buildBytecodeProvider( provider );
Modified: trunk/Hibernate3/src/org/hibernate/impl/SessionFactoryImpl.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/impl/SessionFactoryImpl.java 2006-11-17 22:15:05 UTC (rev 10843)
+++ trunk/Hibernate3/src/org/hibernate/impl/SessionFactoryImpl.java 2006-11-17 22:15:26 UTC (rev 10844)
@@ -348,20 +348,22 @@
}
//checking for named queries
- Map errors = checkNamedQueries();
- if ( !errors.isEmpty() ) {
- Set keys = errors.keySet();
- StringBuffer failingQueries = new StringBuffer( "Errors in named queries: " );
- for ( Iterator iterator = keys.iterator() ; iterator.hasNext() ; ) {
- String queryName = ( String ) iterator.next();
- HibernateException e = ( HibernateException ) errors.get( queryName );
- failingQueries.append( queryName );
- if ( iterator.hasNext() ) {
- failingQueries.append( ", " );
+ if ( settings.isNamedQueryStartupCheckingEnabled() ) {
+ Map errors = checkNamedQueries();
+ if ( !errors.isEmpty() ) {
+ Set keys = errors.keySet();
+ StringBuffer failingQueries = new StringBuffer( "Errors in named queries: " );
+ for ( Iterator iterator = keys.iterator() ; iterator.hasNext() ; ) {
+ String queryName = ( String ) iterator.next();
+ HibernateException e = ( HibernateException ) errors.get( queryName );
+ failingQueries.append( queryName );
+ if ( iterator.hasNext() ) {
+ failingQueries.append( ", " );
+ }
+ log.error( "Error in named query: " + queryName, e );
}
- log.error( "Error in named query: " + queryName, e );
+ throw new HibernateException( failingQueries.toString() );
}
- throw new HibernateException( failingQueries.toString() );
}
//stats
18 years, 1 month