HHH-9642 : Join fetch not performing join fetch for @Embeddable with @OneToMany

This commit is contained in:
Gail Badner 2015-03-05 12:28:38 -08:00
parent 24bafba2b0
commit 6c404c30f7
6 changed files with 301 additions and 3 deletions

View File

@ -298,6 +298,17 @@ public class DotNode extends FromReferenceNode implements DisplayableNode, Selec
String propName = getPath(); String propName = getPath();
FromClause currentFromClause = getWalker().getCurrentFromClause(); FromClause currentFromClause = getWalker().getCurrentFromClause();
// If the lhs of the join is a "component join", we need to go back to the
// first non-component-join as the origin to properly link aliases and
// join columns
FromElement lhsFromElement = getLhs().getFromElement();
while ( lhsFromElement != null && ComponentJoin.class.isInstance( lhsFromElement ) ) {
lhsFromElement = lhsFromElement.getOrigin();
}
if ( lhsFromElement == null ) {
throw new QueryException( "Unable to locate appropriate lhs" );
}
// determine whether we should use the table name or table alias to qualify the column names... // determine whether we should use the table name or table alias to qualify the column names...
// we need to use the table-name when: // we need to use the table-name when:
// 1) the top-level statement is not a SELECT // 1) the top-level statement is not a SELECT
@ -307,7 +318,6 @@ public class DotNode extends FromReferenceNode implements DisplayableNode, Selec
// the alias also, even if the FromElement is the root one... // the alias also, even if the FromElement is the root one...
// //
// in all other cases, we should use the table alias // in all other cases, we should use the table alias
final FromElement lhsFromElement = getLhs().getFromElement();
if ( getWalker().getStatementType() != SqlTokenTypes.SELECT ) { if ( getWalker().getStatementType() != SqlTokenTypes.SELECT ) {
if ( isFromElementUpdateOrDeleteRoot( lhsFromElement ) ) { if ( isFromElementUpdateOrDeleteRoot( lhsFromElement ) ) {
// at this point we know we have the 2 conditions above, // at this point we know we have the 2 conditions above,
@ -330,7 +340,7 @@ public class DotNode extends FromReferenceNode implements DisplayableNode, Selec
// it makes sense to join twice on the same collection role // it makes sense to join twice on the same collection role
FromElementFactory factory = new FromElementFactory( FromElementFactory factory = new FromElementFactory(
currentFromClause, currentFromClause,
getLhs().getFromElement(), lhsFromElement,
propName, propName,
classAlias, classAlias,
getColumns(), getColumns(),

View File

@ -29,6 +29,7 @@ import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import org.hibernate.Hibernate;
import org.hibernate.Query; import org.hibernate.Query;
import org.hibernate.Session; import org.hibernate.Session;
import org.hibernate.Transaction; import org.hibernate.Transaction;
@ -43,6 +44,7 @@ import org.hibernate.test.util.SchemaUtil;
import org.junit.Test; import org.junit.Test;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
@ -407,6 +409,64 @@ public class EmbeddedTest extends BaseNonConfigCoreFunctionalTestCase {
s.close(); s.close();
} }
@Test
@TestForIssue( jiraKey = "HHH-9642")
public void testEmbeddedAndOneToManyHql() throws Exception {
Session s;
s = openSession();
Transaction tx = s.beginTransaction();
InternetProvider provider = new InternetProvider();
provider.setBrandName( "Fido" );
LegalStructure structure = new LegalStructure();
structure.setCountry( "Canada" );
structure.setName( "Rogers" );
provider.setOwner( structure );
s.persist( provider );
Manager manager = new Manager();
manager.setName( "Bill" );
manager.setEmployer( provider );
structure.getTopManagement().add( manager );
s.persist( manager );
tx.commit();
s.close();
s = openSession();
s.getTransaction().begin();
InternetProvider internetProviderQueried =
(InternetProvider) s.createQuery( "from InternetProvider" ).uniqueResult();
assertFalse( Hibernate.isInitialized( internetProviderQueried.getOwner().getTopManagement() ) );
s.getTransaction().commit();
s.close();
s = openSession();
s.getTransaction().begin();
internetProviderQueried =
(InternetProvider) s.createQuery( "from InternetProvider i join fetch i.owner.topManagement" )
.uniqueResult();
assertTrue( Hibernate.isInitialized( internetProviderQueried.getOwner().getTopManagement() ) );
s.getTransaction().commit();
s.close();
s = openSession();
s.getTransaction().begin();
internetProviderQueried =
(InternetProvider) s.createQuery( "from InternetProvider i join fetch i.owner o join fetch o.topManagement" )
.uniqueResult();
assertTrue( Hibernate.isInitialized( internetProviderQueried.getOwner().getTopManagement() ) );
s.getTransaction().commit();
s.close();
s = openSession();
tx = s.beginTransaction();
provider = (InternetProvider) s.get( InternetProvider.class, provider.getId() );
manager = provider.getOwner().getTopManagement().iterator().next();
s.delete( manager );
s.delete( provider );
tx.commit();
s.close();
}
@Test @Test
public void testDefaultCollectionTable() throws Exception { public void testDefaultCollectionTable() throws Exception {
//are the tables correct? //are the tables correct?

View File

@ -317,6 +317,75 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase {
s.close(); s.close();
} }
@Test
@TestForIssue( jiraKey = "HHH-9642")
public void testLazyAssociationInComponent() {
Session session = openSession();
session.getTransaction().begin();
Address address = new Address();
Zoo zoo = new Zoo( "ZOO 1", address );
address.setCity( "City 1" );
StateProvince stateProvince = new StateProvince();
stateProvince.setName( "Illinois" );
session.save( stateProvince );
address.setStateProvince( stateProvince );
session.save( zoo );
session.getTransaction().commit();
session.close();
session = openSession();
session.getTransaction().begin();
zoo = (Zoo) session.createQuery( "from Zoo z" ).uniqueResult();
assertNotNull( zoo );
assertNotNull( zoo.getAddress() );
assertEquals( "City 1", zoo.getAddress().getCity() );
assertFalse( Hibernate.isInitialized( zoo.getAddress().getStateProvince() ) );
assertEquals( "Illinois", zoo.getAddress().getStateProvince().getName() );
assertTrue( Hibernate.isInitialized( zoo.getAddress().getStateProvince() ) );
session.getTransaction().commit();
session.close();
session = openSession();
session.getTransaction().begin();
zoo = (Zoo) session.createQuery( "from Zoo z join fetch z.address.stateProvince" ).uniqueResult();
assertNotNull( zoo );
assertNotNull( zoo.getAddress() );
assertEquals( "City 1", zoo.getAddress().getCity() );
assertTrue( Hibernate.isInitialized( zoo.getAddress().getStateProvince() ) );
assertEquals( "Illinois", zoo.getAddress().getStateProvince().getName() );
session.getTransaction().commit();
session.close();
session = openSession();
session.getTransaction().begin();
zoo = (Zoo) session.createQuery( "from Zoo z join fetch z.address a join fetch a.stateProvince" ).uniqueResult();
assertNotNull( zoo );
assertNotNull( zoo.getAddress() );
assertEquals( "City 1", zoo.getAddress().getCity() );
assertTrue( Hibernate.isInitialized( zoo.getAddress().getStateProvince() ) );
assertEquals( "Illinois", zoo.getAddress().getStateProvince().getName() );
session.getTransaction().commit();
session.close();
session = openSession();
session.getTransaction().begin();
zoo.getAddress().setStateProvince( null );
session.delete( stateProvince );
session.delete( zoo );
session.getTransaction().commit();
session.close();
}
@Test @Test
public void testJPAQLQualifiedIdentificationVariablesControl() { public void testJPAQLQualifiedIdentificationVariablesControl() {
// just checking syntax here... // just checking syntax here...

View File

@ -0,0 +1,77 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2010, Red Hat Inc. 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 Inc.
*
* 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.jpa.test.criteria.components;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
/**
* TODO : javadoc
*
* @author Steve Ebersole
*/
@Entity
public class Alias {
private Long id;
private Name name;
private String source;
public Alias() {
}
public Alias(String firstName, String lastName, String source) {
this( new Name( firstName, lastName ), source );
}
public Alias(Name name, String source) {
this.name = name;
this.source = source;
}
@Id @GeneratedValue
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Name getName() {
return name;
}
public void setName(Name name) {
this.name = name;
}
public String getSource() {
return source;
}
public void setSource(String source) {
this.source = source;
}
}

View File

@ -24,26 +24,33 @@
package org.hibernate.jpa.test.criteria.components; package org.hibernate.jpa.test.criteria.components;
import java.util.List; import java.util.List;
import java.util.Set;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.TypedQuery; import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Fetch;
import javax.persistence.criteria.Root; import javax.persistence.criteria.Root;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.hibernate.Hibernate;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.hibernate.testing.TestForIssue; import org.hibernate.testing.TestForIssue;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/** /**
* @author alan.oleary * @author alan.oleary
*/ */
public class ComponentCriteriaTest extends BaseEntityManagerFunctionalTestCase { public class ComponentCriteriaTest extends BaseEntityManagerFunctionalTestCase {
@Override @Override
public Class[] getAnnotatedClasses() { public Class[] getAnnotatedClasses() {
return new Class[] { Client.class }; return new Class[] { Client.class, Alias.class };
} }
@Test @Test
@ -84,6 +91,66 @@ public class ComponentCriteriaTest extends BaseEntityManagerFunctionalTestCase {
em.close(); em.close();
} }
@Test
@TestForIssue( jiraKey = "HHH-9642")
public void testOneToManyJoinFetchedInEmbeddable() {
EntityManager em = getOrCreateEntityManager();
em.getTransaction().begin();
Client client = new Client( 111, "steve", "ebersole" );
Alias alias = new Alias( "a", "guy", "work" );
client.getName().getAliases().add( alias );
em.persist(client);
em.getTransaction().commit();
em.close();
em = getOrCreateEntityManager();
em.getTransaction().begin();
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Client> cq = cb.createQuery(Client.class);
Root<Client> root = cq.from(Client.class);
root.fetch( Client_.name ).fetch( Name_.aliases );
cq.where(cb.equal(root.get("name").get("firstName"), client.getName().getFirstName()));
List<Client> list = em.createQuery(cq).getResultList();
Assert.assertEquals( 1, list.size() );
client = list.get( 0 );
assertTrue( Hibernate.isInitialized( client.getName().getAliases() ) );
em.getTransaction().commit();
em.close();
em = getOrCreateEntityManager();
em.getTransaction().begin();
TypedQuery< Client > q = em.createQuery(
"SELECT c FROM Client c JOIN FETCH c.name.aliases WHERE c.name.firstName = '"
+ client.getName().getFirstName() + "'",
Client.class
);
Assert.assertEquals( 1, q.getResultList().size() );
client = list.get( 0 );
assertTrue( Hibernate.isInitialized( client.getName().getAliases() ) );
em.getTransaction().commit();
em.close();
em = getOrCreateEntityManager();
em.getTransaction().begin();
q = em.createQuery(
"SELECT c FROM Client c JOIN c.name n join FETCH n.aliases WHERE c.name.firstName = '"
+ client.getName().getFirstName() + "'",
Client.class
);
Assert.assertEquals( 1, q.getResultList().size() );
client = list.get( 0 );
assertTrue( Hibernate.isInitialized( client.getName().getAliases() ) );
em.getTransaction().commit();
em.close();
em = getOrCreateEntityManager();
em.getTransaction().begin();
client = em.merge( client );
em.remove( client );
em.getTransaction().commit();
em.close();
}
@Test @Test
@TestForIssue( jiraKey = "HHH-4586" ) @TestForIssue( jiraKey = "HHH-4586" )
public void testParameterizedFunctions() { public void testParameterizedFunctions() {

View File

@ -21,8 +21,13 @@
*/ */
package org.hibernate.jpa.test.criteria.components; package org.hibernate.jpa.test.criteria.components;
import java.io.Serializable; import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Embeddable; import javax.persistence.Embeddable;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
/** /**
* The name component * The name component
@ -35,6 +40,7 @@ public class Name implements Serializable {
private String firstName; private String firstName;
private String lastName; private String lastName;
private Set<Alias> aliases = new HashSet<Alias>( );
public Name() { public Name() {
} }
@ -61,4 +67,13 @@ public class Name implements Serializable {
public void setLastName(String lastName) { public void setLastName(String lastName) {
this.lastName = lastName; this.lastName = lastName;
} }
@OneToMany(cascade = CascadeType.ALL)
public Set<Alias> getAliases() {
return aliases;
}
public void setAliases(Set<Alias> aliases) {
this.aliases = aliases;
}
} }