|
From: <hib...@li...> - 2006-05-04 16:26:12
|
Author: ste...@jb...
Date: 2006-05-04 12:23:44 -0400 (Thu, 04 May 2006)
New Revision: 9875
Added:
trunk/Hibernate3/test/org/hibernate/test/manytomany/ordered/
trunk/Hibernate3/test/org/hibernate/test/manytomany/ordered/Group.java
trunk/Hibernate3/test/org/hibernate/test/manytomany/ordered/OrderedManyToManyTest.java
trunk/Hibernate3/test/org/hibernate/test/manytomany/ordered/User.java
trunk/Hibernate3/test/org/hibernate/test/manytomany/ordered/UserGroup.hbm.xml
Modified:
trunk/Hibernate3/src/org/hibernate/cfg/HbmBinder.java
trunk/Hibernate3/src/org/hibernate/hibernate-mapping-3.0.dtd
trunk/Hibernate3/src/org/hibernate/hql/ast/HqlSqlWalker.java
trunk/Hibernate3/src/org/hibernate/loader/JoinWalker.java
trunk/Hibernate3/src/org/hibernate/loader/collection/BasicCollectionJoinWalker.java
trunk/Hibernate3/src/org/hibernate/mapping/Collection.java
trunk/Hibernate3/src/org/hibernate/persister/collection/AbstractCollectionPersister.java
trunk/Hibernate3/src/org/hibernate/persister/collection/CollectionPersister.java
trunk/Hibernate3/src/org/hibernate/persister/collection/QueryableCollection.java
Log:
HHH-1414 : many-to-many and order-by
Modified: trunk/Hibernate3/src/org/hibernate/cfg/HbmBinder.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/cfg/HbmBinder.java 2006-05-04 15:10:22 UTC (rev 9874)
+++ trunk/Hibernate3/src/org/hibernate/cfg/HbmBinder.java 2006-05-04 16:23:44 UTC (rev 9875)
@@ -2411,7 +2411,7 @@
false,
mappings
);
- bindManyToManyFilters( collection, subnode, mappings );
+ bindManyToManySubelements( collection, subnode, mappings );
}
else if ( "composite-element".equals( name ) ) {
Component element = new Component( collection );
@@ -2457,7 +2457,7 @@
}
}
- private static void bindManyToManyFilters(
+ private static void bindManyToManySubelements(
Collection collection,
Element manyToManyNode,
Mappings model) throws MappingException {
@@ -2466,6 +2466,11 @@
String whereCondition = where == null ? null : where.getValue();
collection.setManyToManyWhere( whereCondition );
+ // Bind the order-by
+ Attribute order = manyToManyNode.attribute( "order-by" );
+ String orderFragment = order == null ? null : order.getValue();
+ collection.setManyToManyOrdering( orderFragment );
+
// Bind the filters
Iterator filters = manyToManyNode.elementIterator( "filter" );
if ( ( filters.hasNext() || whereCondition != null ) &&
Modified: trunk/Hibernate3/src/org/hibernate/hibernate-mapping-3.0.dtd
===================================================================
--- trunk/Hibernate3/src/org/hibernate/hibernate-mapping-3.0.dtd 2006-05-04 15:10:22 UTC (rev 9874)
+++ trunk/Hibernate3/src/org/hibernate/hibernate-mapping-3.0.dtd 2006-05-04 16:23:44 UTC (rev 9875)
@@ -765,6 +765,7 @@
<!ATTLIST many-to-many foreign-key CDATA #IMPLIED>
<!ATTLIST many-to-many unique (true|false) "false">
<!ATTLIST many-to-many where CDATA #IMPLIED>
+ <!ATTLIST many-to-many order-by CDATA #IMPLIED>
<!ATTLIST many-to-many property-ref CDATA #IMPLIED>
<!-- A composite element allows a collection to hold instances of an arbitrary
Modified: trunk/Hibernate3/src/org/hibernate/hql/ast/HqlSqlWalker.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/hql/ast/HqlSqlWalker.java 2006-05-04 15:10:22 UTC (rev 9874)
+++ trunk/Hibernate3/src/org/hibernate/hql/ast/HqlSqlWalker.java 2006-05-04 16:23:44 UTC (rev 9875)
@@ -558,6 +558,11 @@
.getSQLOrderByString( fromElement.getCollectionTableAlias() );
qn.getOrderByClause().addOrderFragment( orderByFragment );
}
+ if ( fromElement.getQueryableCollection().hasManyToManyOrdering() ) {
+ String orderByFragment = fromElement.getQueryableCollection()
+ .getManyToManyOrderByString( fromElement.getTableAlias() );
+ qn.getOrderByClause().addOrderFragment( orderByFragment );
+ }
}
}
}
Modified: trunk/Hibernate3/src/org/hibernate/loader/JoinWalker.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/loader/JoinWalker.java 2006-05-04 15:10:22 UTC (rev 9874)
+++ trunk/Hibernate3/src/org/hibernate/loader/JoinWalker.java 2006-05-04 16:23:44 UTC (rev 9875)
@@ -717,14 +717,19 @@
}
protected String orderBy(final List associations, final String orderBy) {
- String fullOrderBy = orderBy(associations);
- if ( fullOrderBy.length()== 0 ) {
- fullOrderBy = orderBy;
+ return mergeOrderings( orderBy( associations ), orderBy );
+ }
+
+ protected static String mergeOrderings(String ordering1, String ordering2) {
+ if ( ordering1.length() == 0 ) {
+ return ordering2;
}
- else if ( orderBy.length()!=0 ) {
- fullOrderBy = fullOrderBy + ", " + orderBy;
+ else if ( ordering2.length() == 0 ) {
+ return ordering1;
}
- return fullOrderBy;
+ else {
+ return ordering1 + ", " + ordering2;
+ }
}
/**
@@ -791,15 +796,32 @@
throws MappingException {
StringBuffer buf = new StringBuffer();
Iterator iter = associations.iterator();
+ OuterJoinableAssociation last = null;
while ( iter.hasNext() ) {
OuterJoinableAssociation oj = (OuterJoinableAssociation) iter.next();
- if ( oj.getJoinType()==JoinFragment.LEFT_OUTER_JOIN && oj.getJoinable().isCollection() ) {
- final QueryableCollection queryableCollection = (QueryableCollection) oj.getJoinable();
- if ( queryableCollection.hasOrdering() ) {
- final String orderByString = queryableCollection.getSQLOrderByString( oj.getRHSAlias() );
- buf.append( orderByString ).append(", ");
+ if ( oj.getJoinType() == JoinFragment.LEFT_OUTER_JOIN ) { // why does this matter?
+ if ( oj.getJoinable().isCollection() ) {
+ final QueryableCollection queryableCollection = (QueryableCollection) oj.getJoinable();
+ if ( queryableCollection.hasOrdering() ) {
+ final String orderByString = queryableCollection.getSQLOrderByString( oj.getRHSAlias() );
+ buf.append( orderByString ).append(", ");
+ }
}
+ else {
+ // it might still need to apply a collection ordering based on a
+ // many-to-many defined order-by...
+ if ( last != null && last.getJoinable().isCollection() ) {
+ final QueryableCollection queryableCollection = (QueryableCollection) last.getJoinable();
+ if ( queryableCollection.isManyToMany() && last.isManyToManyWith( oj ) ) {
+ if ( queryableCollection.hasManyToManyOrdering() ) {
+ final String orderByString = queryableCollection.getManyToManyOrderByString( oj.getRHSAlias() );
+ buf.append( orderByString ).append(", ");
+ }
+ }
+ }
+ }
}
+ last = oj;
}
if ( buf.length()>0 ) buf.setLength( buf.length()-2 );
return buf.toString();
Modified: trunk/Hibernate3/src/org/hibernate/loader/collection/BasicCollectionJoinWalker.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/loader/collection/BasicCollectionJoinWalker.java 2006-05-04 15:10:22 UTC (rev 9874)
+++ trunk/Hibernate3/src/org/hibernate/loader/collection/BasicCollectionJoinWalker.java 2006-05-04 16:23:44 UTC (rev 9875)
@@ -81,6 +81,8 @@
subquery,
batchSize
);
+
+ String manyToManyOrderBy = "";
String filter = collectionPersister.filterFragment( alias, getEnabledFilters() );
if ( collectionPersister.isManyToMany() ) {
// from the collection of associations, locate OJA for the
@@ -98,6 +100,7 @@
oja.getRHSAlias(),
getEnabledFilters()
);
+ manyToManyOrderBy += collectionPersister.getManyToManyOrderByString( oja.getRHSAlias() );
}
}
}
@@ -116,7 +119,7 @@
ojf.toWhereFragmentString()
);
- select.setOrderByClause( orderBy(associations, collectionPersister.getSQLOrderByString(alias) ) );
+ select.setOrderByClause( orderBy( associations, mergeOrderings( collectionPersister.getSQLOrderByString(alias), manyToManyOrderBy ) ) );
if ( getFactory().getSettings().isCommentsEnabled() ) {
select.setComment( "load collection " + collectionPersister.getRole() );
Modified: trunk/Hibernate3/src/org/hibernate/mapping/Collection.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/mapping/Collection.java 2006-05-04 15:10:22 UTC (rev 9874)
+++ trunk/Hibernate3/src/org/hibernate/mapping/Collection.java 2006-05-04 16:23:44 UTC (rev 9875)
@@ -40,6 +40,7 @@
private String orderBy;
private String where;
private String manyToManyWhere;
+ private String manyToManyOrderBy;
private PersistentClass owner;
private String referencedPropertyName;
private String nodeName;
@@ -67,7 +68,7 @@
private boolean customDeleteCallable;
private boolean customDeleteAllCallable;
- private String loaderName;
+ private String loaderName;
protected Collection(PersistentClass owner) {
this.owner = owner;
@@ -210,6 +211,14 @@
this.manyToManyWhere = manyToManyWhere;
}
+ public String getManyToManyOrdering() {
+ return manyToManyOrderBy;
+ }
+
+ public void setManyToManyOrdering(String orderFragment) {
+ this.manyToManyOrderBy = orderFragment;
+ }
+
public boolean isIdentified() {
return false;
}
@@ -573,5 +582,4 @@
public String getComparatorClassName() {
return comparatorClassName;
}
-
}
\ No newline at end of file
Modified: trunk/Hibernate3/src/org/hibernate/persister/collection/AbstractCollectionPersister.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/persister/collection/AbstractCollectionPersister.java 2006-05-04 15:10:22 UTC (rev 9874)
+++ trunk/Hibernate3/src/org/hibernate/persister/collection/AbstractCollectionPersister.java 2006-05-04 16:23:44 UTC (rev 9875)
@@ -171,6 +171,9 @@
private final String manyToManyWhereString;
private final String manyToManyWhereTemplate;
+ private final String manyToManyOrderByString;
+ private final String manyToManyOrderByTemplate;
+
// custom sql
private final boolean insertCallable;
private final boolean updateCallable;
@@ -249,7 +252,9 @@
hasOrphanDelete = collection.hasOrphanDelete();
int batch = collection.getBatchSize();
- if (batch==-1) batch = factory.getSettings().getDefaultBatchFetchSize();
+ if ( batch == -1 ) {
+ batch = factory.getSettings().getDefaultBatchFetchSize();
+ }
batchSize = batch;
isVersioned = collection.isOptimisticLocked();
@@ -313,7 +318,9 @@
elementColumnNames[j] = col.getQuotedName(dialect);
elementColumnIsSettable[j] = true;
elementColumnIsInPrimaryKey[j] = !col.isNullable();
- if ( !col.isNullable() ) hasNotNullableColumns = true;
+ if ( !col.isNullable() ) {
+ hasNotNullableColumns = true;
+ }
isPureFormula = false;
}
j++;
@@ -323,7 +330,9 @@
//workaround, for backward compatibility of sets with no
//not-null columns, assume all columns are used in the
//row locator SQL
- if ( !hasNotNullableColumns ) Arrays.fill(elementColumnIsInPrimaryKey, true);
+ if ( !hasNotNullableColumns ) {
+ Arrays.fill( elementColumnIsInPrimaryKey, true );
+ }
// INDEX AND ROW SELECT
@@ -496,6 +505,10 @@
manyToManyWhereTemplate = manyToManyWhereString == null ?
null :
Template.renderWhereStringTemplate( manyToManyWhereString, factory.getDialect() );
+ manyToManyOrderByString = collection.getManyToManyOrdering();
+ manyToManyOrderByTemplate = manyToManyOrderByString == null
+ ? null
+ : Template.renderOrderByStringTemplate( manyToManyOrderByString, factory.getDialect() );
initCollectionPropertyMap();
}
@@ -509,10 +522,18 @@
protected void logStaticSQL() {
if ( log.isDebugEnabled() ) {
log.debug( "Static SQL for collection: " + getRole() );
- if ( getSQLInsertRowString() != null ) log.debug( " Row insert: " + getSQLInsertRowString() );
- if ( getSQLUpdateRowString() != null ) log.debug( " Row update: " + getSQLUpdateRowString() );
- if ( getSQLDeleteRowString() != null ) log.debug( " Row delete: " + getSQLDeleteRowString() );
- if ( getSQLDeleteString() != null ) log.debug( " One-shot delete: " + getSQLDeleteString() );
+ if ( getSQLInsertRowString() != null ) {
+ log.debug( " Row insert: " + getSQLInsertRowString() );
+ }
+ if ( getSQLUpdateRowString() != null ) {
+ log.debug( " Row update: " + getSQLUpdateRowString() );
+ }
+ if ( getSQLDeleteRowString() != null ) {
+ log.debug( " Row delete: " + getSQLDeleteRowString() );
+ }
+ if ( getSQLDeleteString() != null ) {
+ log.debug( " One-shot delete: " + getSQLDeleteString() );
+ }
}
}
@@ -539,9 +560,11 @@
}
private CollectionInitializer getSubselectInitializer(Serializable key, SessionImplementor session) {
+
+ if ( !isSubselectLoadable() ) {
+ return null;
+ }
- if ( !isSubselectLoadable() ) return null;
-
final PersistenceContext persistenceContext = session.getPersistenceContext();
SubselectFetch subselect = persistenceContext.getBatchFetchQueue()
@@ -592,6 +615,14 @@
StringHelper.replace( sqlOrderByStringTemplate, Template.TEMPLATE, alias ) : "";
}
+ public String getManyToManyOrderByString(String alias) {
+ if ( isManyToMany() && manyToManyOrderByString != null ) {
+ return StringHelper.replace( manyToManyOrderByTemplate, Template.TEMPLATE, alias );
+ }
+ else {
+ return "";
+ }
+ }
public FetchMode getFetchMode() {
return fetchMode;
}
@@ -600,6 +631,10 @@
return hasOrder;
}
+ public boolean hasManyToManyOrdering() {
+ return isManyToMany() && manyToManyOrderByTemplate != null;
+ }
+
public boolean hasWhere() {
return hasWhere;
}
@@ -817,7 +852,9 @@
}
protected String generateDetectRowByIndexString() {
- if ( !hasIndex() ) return null;
+ if ( !hasIndex() ) {
+ return null;
+ }
return new SimpleSelect(dialect)
.setTableName( getTableName() )
.addCondition( getKeyColumnNames(), "=?" )
@@ -828,7 +865,9 @@
}
protected String generateSelectRowByIndexString() {
- if ( !hasIndex() ) return null;
+ if ( !hasIndex() ) {
+ return null;
+ }
return new SimpleSelect(dialect)
.setTableName( getTableName() )
.addCondition( getKeyColumnNames(), "=?" )
@@ -881,7 +920,9 @@
}
protected void appendIdentifierColumns(SelectFragment frag, String alias) {
- if ( hasIdentifier ) frag.addColumn( alias, identifierColumnName, identifierColumnAlias );
+ if ( hasIdentifier ) {
+ frag.addColumn( alias, identifierColumnName, identifierColumnAlias );
+ }
}
public String[] getIndexColumnNames() {
@@ -974,7 +1015,9 @@
throw sqle;
}
- if ( log.isDebugEnabled() ) log.debug( "done deleting collection" );
+ if ( log.isDebugEnabled() ) {
+ log.debug( "done deleting collection" );
+ }
}
catch ( SQLException sqle ) {
throw JDBCExceptionHelper.convert(
@@ -1042,7 +1085,9 @@
}
i++;
}
- if ( log.isDebugEnabled() ) log.debug( "done inserting collection: " + count + " rows inserted" );
+ if ( log.isDebugEnabled() ) {
+ log.debug( "done inserting collection: " + count + " rows inserted" );
+ }
}
catch ( SQLException sqle ) {
session.getBatcher().abortBatch( sqle );
@@ -1051,7 +1096,9 @@
}
else {
- if ( log.isDebugEnabled() ) log.debug( "collection was empty" );
+ if ( log.isDebugEnabled() ) {
+ log.debug( "collection was empty" );
+ }
}
}
catch ( SQLException sqle ) {
@@ -1130,10 +1177,14 @@
throw sqle;
}
- if ( log.isDebugEnabled() ) log.debug( "done deleting collection rows: " + count + " deleted" );
+ if ( log.isDebugEnabled() ) {
+ log.debug( "done deleting collection rows: " + count + " deleted" );
+ }
}
else {
- if ( log.isDebugEnabled() ) log.debug( "no rows to delete" );
+ if ( log.isDebugEnabled() ) {
+ log.debug( "no rows to delete" );
+ }
}
}
catch ( SQLException sqle ) {
@@ -1205,7 +1256,9 @@
}
i++;
}
- if ( log.isDebugEnabled() ) log.debug( "done inserting rows: " + count + " inserted" );
+ if ( log.isDebugEnabled() ) {
+ log.debug( "done inserting rows: " + count + " inserted" );
+ }
}
catch ( SQLException sqle ) {
session.getBatcher().abortBatch( sqle );
@@ -1251,7 +1304,9 @@
}
public Type toType(String propertyName) throws QueryException {
- if ( "index".equals( propertyName ) ) return indexType;
+ if ( "index".equals( propertyName ) ) {
+ return indexType;
+ }
return elementPropertyMapping.toType( propertyName );
}
@@ -1304,7 +1359,9 @@
}
public EntityPersister getElementPersister() {
- if ( elementPersister == null ) throw new AssertionFailure( "not an association" );
+ if ( elementPersister == null ) {
+ throw new AssertionFailure( "not an association" );
+ }
return ( Loadable ) elementPersister;
}
@@ -1428,8 +1485,10 @@
public String[] getCollectionPropertyColumnAliases(String propertyName, String suffix) {
String rawAliases[] = (String[]) collectionPropertyColumnAliases.get(propertyName);
-
- if(rawAliases==null) return null;
+
+ if ( rawAliases == null ) {
+ return null;
+ }
String result[] = new String[rawAliases.length];
for ( int i=0; i<rawAliases.length; i++ ) {
Modified: trunk/Hibernate3/src/org/hibernate/persister/collection/CollectionPersister.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/persister/collection/CollectionPersister.java 2006-05-04 15:10:22 UTC (rev 9874)
+++ trunk/Hibernate3/src/org/hibernate/persister/collection/CollectionPersister.java 2006-05-04 16:23:44 UTC (rev 9875)
@@ -203,6 +203,9 @@
* that happens in memory, as in the case of a sorted collection.)
*/
public boolean hasOrdering();
+
+ public boolean hasManyToManyOrdering();
+
/**
* Get the "space" that holds the persistent state
*/
Modified: trunk/Hibernate3/src/org/hibernate/persister/collection/QueryableCollection.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/persister/collection/QueryableCollection.java 2006-05-04 15:10:22 UTC (rev 9874)
+++ trunk/Hibernate3/src/org/hibernate/persister/collection/QueryableCollection.java 2006-05-04 16:23:44 UTC (rev 9875)
@@ -46,7 +46,16 @@
* Get the order by SQL
*/
public abstract String getSQLOrderByString(String alias);
+
/**
+ * Get the order-by to be applied at the target table of a many to many
+ *
+ * @param alias The alias for the many-to-many target table
+ * @return appropriate order-by fragment or empty string.
+ */
+ public abstract String getManyToManyOrderByString(String alias);
+
+ /**
* Does this collection role have a where clause filter?
*/
public abstract boolean hasWhere();
Added: trunk/Hibernate3/test/org/hibernate/test/manytomany/ordered/Group.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/manytomany/ordered/Group.java 2006-05-04 15:10:22 UTC (rev 9874)
+++ trunk/Hibernate3/test/org/hibernate/test/manytomany/ordered/Group.java 2006-05-04 16:23:44 UTC (rev 9875)
@@ -0,0 +1,69 @@
+package org.hibernate.test.manytomany.ordered;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.ArrayList;
+
+public class Group implements Serializable {
+
+ private Long id;
+ private String org;
+ private String name;
+ private String description;
+
+ private List users = new ArrayList();
+
+ public Group() {
+ }
+
+ public Group(String name, String org) {
+ this.org = org;
+ this.name = name;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getOrg() {
+ return org;
+ }
+
+ public void setOrg(String org) {
+ this.org = org;
+ }
+
+ public List getUsers() {
+ return users;
+ }
+
+ public void setUsers(List users) {
+ this.users = users;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public void addUser(User user) {
+ if ( user.getGroups().add( this ) ) {
+ getUsers().add( user );
+ }
+ }
+}
Added: trunk/Hibernate3/test/org/hibernate/test/manytomany/ordered/OrderedManyToManyTest.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/manytomany/ordered/OrderedManyToManyTest.java 2006-05-04 15:10:22 UTC (rev 9874)
+++ trunk/Hibernate3/test/org/hibernate/test/manytomany/ordered/OrderedManyToManyTest.java 2006-05-04 16:23:44 UTC (rev 9875)
@@ -0,0 +1,137 @@
+package org.hibernate.test.manytomany.ordered;
+
+import org.hibernate.test.TestCase;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.Hibernate;
+import org.hibernate.FetchMode;
+import org.hibernate.Criteria;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import java.util.List;
+
+/**
+ * @author Gavin King
+ */
+public class OrderedManyToManyTest extends TestCase {
+
+ public OrderedManyToManyTest(String str) {
+ super(str);
+ }
+
+ public void testManyToManyOrdering() {
+ Session s = openSession();
+ Transaction t = s.beginTransaction();
+ User gavin = new User( "gavin", "jboss" );
+ User steve = new User( "steve", "jboss" );
+ User max = new User( "max", "jboss" );
+ User emmanuel = new User( "emmanuel", "jboss" );
+ s.persist( gavin );
+ s.persist( steve );
+ s.persist( max );
+ s.persist( emmanuel );
+ Group hibernate = new Group( "hibernate", "jboss" );
+ hibernate.addUser( gavin );
+ hibernate.addUser( steve );
+ hibernate.addUser( max );
+ hibernate.addUser( emmanuel );
+ s.persist( hibernate );
+ t.commit();
+ s.close();
+
+ // delayed collection load...
+ s = openSession();
+ t = s.beginTransaction();
+ hibernate = ( Group ) s.get( Group.class, hibernate.getId() );
+ assertFalse( Hibernate.isInitialized( hibernate.getUsers() ) );
+ assertEquals( 4, hibernate.getUsers().size() );
+ assertOrdering( hibernate.getUsers() );
+ t.commit();
+ s.close();
+
+ // HQL (non eager)
+ s = openSession();
+ t = s.beginTransaction();
+ hibernate = ( Group ) s.createQuery( "from Group" ).uniqueResult();
+ assertFalse( Hibernate.isInitialized( hibernate.getUsers() ) );
+ assertEquals( 4, hibernate.getUsers().size() );
+ assertOrdering( hibernate.getUsers() );
+ t.commit();
+ s.close();
+
+ // HQL (eager)
+ s = openSession();
+ t = s.beginTransaction();
+ hibernate = ( Group ) s.createQuery( "from Group g inner join fetch g.users" ).uniqueResult();
+ assertTrue( Hibernate.isInitialized( hibernate.getUsers() ) );
+ assertEquals( 4, hibernate.getUsers().size() );
+ assertOrdering( hibernate.getUsers() );
+ t.commit();
+ s.close();
+
+ // criteria load (forced eager fetch)
+ s = openSession();
+ t = s.beginTransaction();
+ Criteria criteria = s.createCriteria( Group.class );
+ criteria.setFetchMode( "users", FetchMode.JOIN );
+ hibernate = ( Group ) criteria.uniqueResult();
+ assertTrue( Hibernate.isInitialized( hibernate.getUsers() ) );
+ assertEquals( 4, hibernate.getUsers().size() );
+ assertOrdering( hibernate.getUsers() );
+ t.commit();
+ s.close();
+
+ // criteria load (forced non eager fetch)
+ s = openSession();
+ t = s.beginTransaction();
+ criteria = s.createCriteria( Group.class );
+ criteria.setFetchMode( "users", FetchMode.SELECT );
+ hibernate = ( Group ) criteria.uniqueResult();
+ assertFalse( Hibernate.isInitialized( hibernate.getUsers() ) );
+ assertEquals( 4, hibernate.getUsers().size() );
+ assertOrdering( hibernate.getUsers() );
+ t.commit();
+ s.close();
+
+ // clean up
+ s = openSession();
+ t = s.beginTransaction();
+ s.delete( gavin );
+ s.delete( steve );
+ s.delete( max );
+ s.delete( emmanuel );
+ s.delete( hibernate );
+ t.commit();
+ s.close();
+ }
+
+ private void assertOrdering(List users) {
+ User user = extractUser( users, 0 );
+ assertTrue( "many-to-many ordering not applied", user.getName().equals( "emmanuel" ) );
+ user = extractUser( users, 1 );
+ assertTrue( "many-to-many ordering not applied", user.getName().equals( "gavin" ) );
+ user = extractUser( users, 2 );
+ assertTrue( "many-to-many ordering not applied", user.getName().equals( "max" ) );
+ user = extractUser( users, 3 );
+ assertTrue( "many-to-many ordering not applied", user.getName().equals( "steve" ) );
+ }
+
+ private User extractUser(List users, int position) {
+ return ( User ) users.get( position );
+ }
+ protected String[] getMappings() {
+ return new String[] { "manytomany/ordered/UserGroup.hbm.xml" };
+ }
+
+ public static Test suite() {
+ return new TestSuite( OrderedManyToManyTest.class);
+ }
+
+ protected void configure(Configuration cfg) {
+ cfg.setProperty( Environment.USE_SECOND_LEVEL_CACHE, "false");
+ }
+
+}
Added: trunk/Hibernate3/test/org/hibernate/test/manytomany/ordered/User.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/manytomany/ordered/User.java 2006-05-04 15:10:22 UTC (rev 9874)
+++ trunk/Hibernate3/test/org/hibernate/test/manytomany/ordered/User.java 2006-05-04 16:23:44 UTC (rev 9875)
@@ -0,0 +1,54 @@
+package org.hibernate.test.manytomany.ordered;
+
+import java.io.Serializable;
+import java.util.Set;
+import java.util.HashSet;
+
+public class User implements Serializable {
+
+ private Long id;
+ private String org;
+ private String name;
+ private Set groups = new HashSet();
+
+ public User() {
+ }
+
+ public User(String name, String org) {
+ this.org = org;
+ this.name = name;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getOrg() {
+ return org;
+ }
+
+ public void setOrg(String org) {
+ this.org = org;
+ }
+
+ public Set getGroups() {
+ return groups;
+ }
+
+ public void setGroups(Set groups) {
+ this.groups = groups;
+ }
+
+}
Added: trunk/Hibernate3/test/org/hibernate/test/manytomany/ordered/UserGroup.hbm.xml
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/manytomany/ordered/UserGroup.hbm.xml 2006-05-04 15:10:22 UTC (rev 9874)
+++ trunk/Hibernate3/test/org/hibernate/test/manytomany/ordered/UserGroup.hbm.xml 2006-05-04 16:23:44 UTC (rev 9875)
@@ -0,0 +1,42 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+ "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+ "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+
+ This mapping demonstrates how to map a many-to-many
+ association with a shared attribute in the primary keys
+ of the associated entities.
+
+-->
+
+<hibernate-mapping
+ package="org.hibernate.test.manytomany.ordered">
+
+
+ <class name="User" table="`User`">
+ <id name="id" column="ID" type="long">
+ <generator class="native"/>
+ </id>
+ <property name="name" column="NAME"/>
+ <property name="org" column="ORG"/>
+ <set name="groups" table="UserGroup">
+ <key column="USER_ID"/>
+ <many-to-many column="GROUP_ID" class="Group"/>
+ </set>
+ </class>
+
+ <class name="Group" table="`Group`">
+ <id name="id" column="ID">
+ <generator class="native"/>
+ </id>
+ <property name="name"/>
+ <property name="description"/>
+ <bag name="users" table="UserGroup" inverse="true">
+ <key column="GROUP_ID"/>
+ <many-to-many column="USER_ID" class="User" order-by="NAME"/>
+ </bag>
+ </class>
+
+</hibernate-mapping>
|