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