From 718fd34f4ba50813df0d3162634fabb7a3c57641 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Thu, 5 Mar 2009 22:12:56 +0000 Subject: [PATCH] HHH-3528 - FETCH JOIN query doesn't work in a StatelessSession git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@16091 1b8cb986-b30d-0410-93ca-fae66ebed9b2 --- .../hibernate/impl/StatelessSessionImpl.java | 25 +-- .../test/stateless/fetching/Mappings.hbm.xml | 56 +++++++ .../test/stateless/fetching/Resource.java | 65 ++++++++ .../StatelessSessionFetchingTest.java | 150 ++++++++++++++++++ .../test/stateless/fetching/Task.java | 111 +++++++++++++ .../test/stateless/fetching/User.java | 55 +++++++ 6 files changed, 452 insertions(+), 10 deletions(-) create mode 100644 testsuite/src/test/java/org/hibernate/test/stateless/fetching/Mappings.hbm.xml create mode 100644 testsuite/src/test/java/org/hibernate/test/stateless/fetching/Resource.java create mode 100644 testsuite/src/test/java/org/hibernate/test/stateless/fetching/StatelessSessionFetchingTest.java create mode 100644 testsuite/src/test/java/org/hibernate/test/stateless/fetching/Task.java create mode 100644 testsuite/src/test/java/org/hibernate/test/stateless/fetching/User.java diff --git a/core/src/main/java/org/hibernate/impl/StatelessSessionImpl.java b/core/src/main/java/org/hibernate/impl/StatelessSessionImpl.java index e339d6d91b..9a1743e108 100755 --- a/core/src/main/java/org/hibernate/impl/StatelessSessionImpl.java +++ b/core/src/main/java/org/hibernate/impl/StatelessSessionImpl.java @@ -1,7 +1,5 @@ /* - * Hibernate, Relational Persistence for Idiomatic Java - * - * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as + * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. All third-party contributions are * distributed under license by Red Hat Middleware LLC. @@ -20,7 +18,6 @@ * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA - * */ package org.hibernate.impl; @@ -264,13 +261,21 @@ public class StatelessSessionImpl extends AbstractSessionImpl boolean eager, boolean nullable) throws HibernateException { errorIfClosed(); - EntityPersister persister = getFactory().getEntityPersister(entityName); - if ( !eager && persister.hasProxy() ) { - return persister.createProxy(id, this); + EntityPersister persister = getFactory().getEntityPersister( entityName ); + // first, try to load it from the temp PC associated to this SS + Object loaded = temporaryPersistenceContext.getEntity( new EntityKey( id, persister, getEntityMode() ) ); + if ( loaded != null ) { + // we found it in the temp PC. Should indicate we are in the midst of processing a result set + // containing eager fetches via join fetch + return loaded; } - Object loaded = temporaryPersistenceContext.getEntity( new EntityKey(id, persister, EntityMode.POJO) ); - //TODO: if not loaded, throw an exception - return loaded==null ? get( entityName, id ) : loaded; + if ( !eager && persister.hasProxy() ) { + // if the metadata allowed proxy creation and caller did not request forceful eager loading, + // generate a proxy + return persister.createProxy( id, this ); + } + // otherwise immediately materialize it + return get( entityName, id ); } public Iterator iterate(String query, QueryParameters queryParameters) throws HibernateException { diff --git a/testsuite/src/test/java/org/hibernate/test/stateless/fetching/Mappings.hbm.xml b/testsuite/src/test/java/org/hibernate/test/stateless/fetching/Mappings.hbm.xml new file mode 100644 index 0000000000..70abf34a2d --- /dev/null +++ b/testsuite/src/test/java/org/hibernate/test/stateless/fetching/Mappings.hbm.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/testsuite/src/test/java/org/hibernate/test/stateless/fetching/Resource.java b/testsuite/src/test/java/org/hibernate/test/stateless/fetching/Resource.java new file mode 100644 index 0000000000..fe36d57d48 --- /dev/null +++ b/testsuite/src/test/java/org/hibernate/test/stateless/fetching/Resource.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Middleware LLC. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.test.stateless.fetching; + +/** + * TODO : javadoc + * + * @author Steve Ebersole + */ +public class Resource { + private Long id; + private String name; + private User owner; + + public Resource() { + } + + public Resource(String name, User owner) { + this.name = name; + this.owner = owner; + } + + 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 User getOwner() { + return owner; + } + + public void setOwner(User owner) { + this.owner = owner; + } +} diff --git a/testsuite/src/test/java/org/hibernate/test/stateless/fetching/StatelessSessionFetchingTest.java b/testsuite/src/test/java/org/hibernate/test/stateless/fetching/StatelessSessionFetchingTest.java new file mode 100644 index 0000000000..b8a0c4042d --- /dev/null +++ b/testsuite/src/test/java/org/hibernate/test/stateless/fetching/StatelessSessionFetchingTest.java @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Middleware LLC. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.test.stateless.fetching; + +import java.util.Date; + +import junit.framework.Test; + +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.ImprovedNamingStrategy; +import org.hibernate.cfg.DefaultNamingStrategy; +import org.hibernate.util.StringHelper; +import org.hibernate.Session; +import org.hibernate.StatelessSession; +import org.hibernate.Hibernate; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * TODO : javadoc + * + * @author Steve Ebersole + */ +public class StatelessSessionFetchingTest extends FunctionalTestCase { + private static final Logger log = LoggerFactory.getLogger( StatelessSessionFetchingTest.class ); + + public StatelessSessionFetchingTest(String name) { + super( name ); + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( StatelessSessionFetchingTest.class ); + } + + public String[] getMappings() { + return new String[] { "stateless/fetching/Mappings.hbm.xml" }; + } + + // trying a new thing here in tests with this naming strategy to help alleviate table name clashes + + private class TestingNamingStrategy extends DefaultNamingStrategy { + private final String prefix = determineUniquePrefix(); + + protected String applyPrefix(String baseTableName) { + String prefixed = prefix + '_' + baseTableName; + log.debug( "prefixed table name : {} -> {} ", baseTableName, prefixed ); + return prefixed; + } + + @Override + public String classToTableName(String className) { + return applyPrefix( super.classToTableName( className ) ); + } + + @Override + public String tableName(String tableName) { + if ( tableName.startsWith( "`" ) && tableName.endsWith( "`" ) ) { + return tableName; + } + if ( tableName.startsWith( prefix + '_' ) ) { + return tableName; + } + return applyPrefix( tableName ); + } + + @Override + public String collectionTableName(String ownerEntity, String ownerEntityTable, String associatedEntity, String associatedEntityTable, String propertyName) { + String tableName = super.collectionTableName( ownerEntity, ownerEntityTable, associatedEntity, associatedEntityTable, propertyName ); + return applyPrefix( tableName ); + } + + @Override + public String logicalCollectionTableName(String tableName, String ownerEntityTable, String associatedEntityTable, String propertyName) { + String resolvedTableName = prefix + '_' + super.logicalCollectionTableName( tableName, ownerEntityTable, associatedEntityTable, propertyName ); + System.out.println( "Logical collection table name : " + tableName + " -> " + resolvedTableName ); + return resolvedTableName; + } + + private String determineUniquePrefix() { + return StringHelper.collapseQualifier( getClass().getName(), false ).toUpperCase(); + } + } + + @Override + public void configure(Configuration cfg) { + super.configure( cfg ); + cfg.setNamingStrategy( new TestingNamingStrategy() ); + } + + public void testDynamicFetch() { + Session s = openSession(); + s.beginTransaction(); + Date now = new Date(); + User me = new User( "me" ); + User you = new User( "you" ); + Resource yourClock = new Resource( "clock", you ); + Task task = new Task( me, "clean", yourClock, now ); // :) + s.save( me ); + s.save( you ); + s.save( yourClock ); + s.save( task ); + s.getTransaction().commit(); + s.close(); + + StatelessSession ss = sfi().openStatelessSession(); + ss.beginTransaction(); + Task taskRef = ( Task ) ss.createQuery( "from Task t join fetch t.resource join fetch t.user" ).uniqueResult(); + assertTrue( taskRef != null ); + assertTrue( Hibernate.isInitialized( taskRef ) ); + assertTrue( Hibernate.isInitialized( taskRef.getUser() ) ); + assertTrue( Hibernate.isInitialized( taskRef.getResource() ) ); + assertFalse( Hibernate.isInitialized( taskRef.getResource().getOwner() ) ); + ss.getTransaction().commit(); + ss.close(); + + cleanup(); + } + + private void cleanup() { + Session s = openSession(); + s.beginTransaction(); + s.createQuery( "delete Task" ).executeUpdate(); + s.createQuery( "delete Resource" ).executeUpdate(); + s.createQuery( "delete User" ).executeUpdate(); + s.getTransaction().commit(); + s.close(); + } +} diff --git a/testsuite/src/test/java/org/hibernate/test/stateless/fetching/Task.java b/testsuite/src/test/java/org/hibernate/test/stateless/fetching/Task.java new file mode 100644 index 0000000000..55ec75999a --- /dev/null +++ b/testsuite/src/test/java/org/hibernate/test/stateless/fetching/Task.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Middleware LLC. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.test.stateless.fetching; + +import java.util.Date; + +/** + * TODO : javadoc + * + * @author Steve Ebersole + */ +public class Task { + private Long id; + private String description; + private User user; + private Resource resource; + private Date dueDate; + private Date startDate; + private Date completionDate; + + public Task() { + } + + public Task(User user, String description, Resource resource, Date dueDate) { + this( user, description, resource, dueDate, null, null ); + } + + public Task(User user, String description, Resource resource, Date dueDate, Date startDate, Date completionDate) { + this.user = user; + this.resource = resource; + this.description = description; + this.dueDate = dueDate; + this.startDate = startDate; + this.completionDate = completionDate; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + + public Resource getResource() { + return resource; + } + + public void setResource(Resource resource) { + this.resource = resource; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Date getDueDate() { + return dueDate; + } + + public void setDueDate(Date dueDate) { + this.dueDate = dueDate; + } + + public Date getStartDate() { + return startDate; + } + + public void setStartDate(Date startDate) { + this.startDate = startDate; + } + + public Date getCompletionDate() { + return completionDate; + } + + public void setCompletionDate(Date completionDate) { + this.completionDate = completionDate; + } +} diff --git a/testsuite/src/test/java/org/hibernate/test/stateless/fetching/User.java b/testsuite/src/test/java/org/hibernate/test/stateless/fetching/User.java new file mode 100644 index 0000000000..b301bb007b --- /dev/null +++ b/testsuite/src/test/java/org/hibernate/test/stateless/fetching/User.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Middleware LLC. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.test.stateless.fetching; + +/** + * TODO : javadoc + * + * @author Steve Ebersole + */ +public class User { + private Long id; + private String name; + + public User() { + } + + public User(String name) { + 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; + } +}