From 7c69c7fb95033a46a00d1ec14af767634137cd6c Mon Sep 17 00:00:00 2001 From: Brett Meyer Date: Tue, 14 Jan 2014 22:51:03 -0500 Subject: [PATCH] HHH-8855 HHH-8640 corrected EntityGraph loadplan strategy, support inheritance in SubGraphs --- .../query/spi/EntityGraphQueryHint.java | 9 +- ...AbstractEntityGraphVisitationStrategy.java | 77 ++++++---------- .../jpa/graph/internal/SubgraphImpl.java | 2 +- .../hibernate/jpa/test/graphs/Company.java | 54 +++++++++++ .../hibernate/jpa/test/graphs/Employee.java | 48 ++++++++++ ...tyGraphTests.java => EntityGraphTest.java} | 83 +++++++++++++---- .../hibernate/jpa/test/graphs/Location.java | 38 ++++++++ .../hibernate/jpa/test/graphs/Manager.java | 32 +++++++ .../org/hibernate/jpa/test/graphs/Market.java | 29 ++++++ .../queryhint/QueryHintEntityGraphTest.java | 89 +++++-------------- 10 files changed, 325 insertions(+), 136 deletions(-) create mode 100644 hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/graphs/Company.java create mode 100644 hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/graphs/Employee.java rename hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/graphs/{find/FindEntityGraphTests.java => EntityGraphTest.java} (53%) create mode 100644 hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/graphs/Location.java create mode 100644 hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/graphs/Manager.java create mode 100644 hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/graphs/Market.java diff --git a/hibernate-core/src/main/java/org/hibernate/engine/query/spi/EntityGraphQueryHint.java b/hibernate-core/src/main/java/org/hibernate/engine/query/spi/EntityGraphQueryHint.java index 82ba32c713..4d87976523 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/query/spi/EntityGraphQueryHint.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/query/spi/EntityGraphQueryHint.java @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; + import javax.persistence.AttributeNode; import javax.persistence.EntityGraph; import javax.persistence.Subgraph; @@ -36,6 +37,7 @@ import org.hibernate.hql.internal.ast.tree.FromElement; import org.hibernate.hql.internal.ast.tree.FromElementFactory; import org.hibernate.persister.collection.QueryableCollection; import org.hibernate.sql.JoinType; +import org.hibernate.type.CollectionType; import org.hibernate.type.EntityType; import org.hibernate.type.Type; @@ -85,6 +87,8 @@ public class EntityGraphQueryHint { final String attributeName = attributeNode.getAttributeName(); final String className = origin.getClassName(); + // TODO: This is ignored by collection types and probably wrong for entity types. Presumably it screws + // with inheritance. final String role = className + "." + attributeName; final String classAlias = origin.getClassAlias(); final String originTableAlias = origin.getTableAlias(); @@ -120,6 +124,7 @@ public class EntityGraphQueryHint { ); } else if ( propertyType.isCollectionType() ) { + CollectionType collectionType = (CollectionType) propertyType; final String[] columns = origin.toColumns( originTableAlias, attributeName, false ); final FromElementFactory fromElementFactory = new FromElementFactory( @@ -127,9 +132,9 @@ public class EntityGraphQueryHint { attributeName, classAlias, columns, false ); final QueryableCollection queryableCollection = walker.getSessionFactoryHelper() - .requireQueryableCollection( role ); + .requireQueryableCollection( collectionType.getRole() ); fromElement = fromElementFactory.createCollection( - queryableCollection, role, JoinType.LEFT_OUTER_JOIN, true, false + queryableCollection, collectionType.getRole(), JoinType.LEFT_OUTER_JOIN, true, false ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/build/internal/AbstractEntityGraphVisitationStrategy.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/build/internal/AbstractEntityGraphVisitationStrategy.java index 2387bf34a2..51f5bf4c7d 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/plan/build/internal/AbstractEntityGraphVisitationStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/build/internal/AbstractEntityGraphVisitationStrategy.java @@ -49,10 +49,8 @@ import org.hibernate.loader.plan.spi.LoadPlan; import org.hibernate.loader.plan.spi.Return; import org.hibernate.persister.walking.spi.AssociationAttributeDefinition; import org.hibernate.persister.walking.spi.AttributeDefinition; -import org.hibernate.persister.walking.spi.CollectionDefinition; import org.hibernate.persister.walking.spi.CollectionElementDefinition; import org.hibernate.persister.walking.spi.CollectionIndexDefinition; -import org.hibernate.persister.walking.spi.CompositionDefinition; import org.hibernate.persister.walking.spi.EntityDefinition; import org.hibernate.persister.walking.spi.WalkingException; import org.jboss.logging.Logger; @@ -73,6 +71,7 @@ import org.jboss.logging.Logger; * it is not, then depends on which property is used to apply this entity graph. * * @author Strong Liu + * @author Brett Meyer */ public abstract class AbstractEntityGraphVisitationStrategy extends AbstractLoadPlanBuildingAssociationVisitationStrategy { @@ -87,10 +86,14 @@ public abstract class AbstractEntityGraphVisitationStrategy protected static final FetchStrategy DEFAULT_EAGER = new FetchStrategy( FetchTiming.IMMEDIATE, FetchStyle.JOIN ); protected static final FetchStrategy DEFAULT_LAZY = new FetchStrategy( FetchTiming.DELAYED, FetchStyle.SELECT ); protected final LoadQueryInfluencers loadQueryInfluencers; - protected final ArrayDeque graphStack = new ArrayDeque(); - protected final ArrayDeque attributeStack = new ArrayDeque(); - //the attribute nodes defined in the current graph node (entity graph or subgraph) we're working on - protected Map attributeNodeImplementorMap = Collections.emptyMap(); + // Queue containing entity/sub graphs to be visited. + private final ArrayDeque graphStack = new ArrayDeque(); + // Queue containing attributes being visited, used eventually to determine the fetch strategy. + private final ArrayDeque attributeStack = new ArrayDeque(); + // Queue of maps containing the current graph node's attributes. Used for fast lookup, instead of iterating + // over graphStack.peekLast().attributeImplementorNodes(). + private final ArrayDeque> attributeMapStack + = new ArrayDeque>(); private EntityReturn rootEntityReturn; private final LockMode lockMode; @@ -106,24 +109,21 @@ public abstract class AbstractEntityGraphVisitationStrategy public void start() { super.start(); graphStack.addLast( getRootEntityGraph() ); - attributeNodeImplementorMap = buildAttributeNodeMap(); } @Override public void finish() { super.finish(); graphStack.removeLast(); - attributeNodeImplementorMap = Collections.emptyMap(); //applying a little internal stack checking - if ( !graphStack.isEmpty() || !attributeStack.isEmpty() || !attributeNodeImplementorMap.isEmpty() ) { + if ( !graphStack.isEmpty() || !attributeStack.isEmpty() || !attributeMapStack.isEmpty() ) { throw new WalkingException( "Internal stack error" ); } } @Override public void startingEntity(final EntityDefinition entityDefinition) { - //TODO check if the passed in entity definition is the same as the root entity graph (a.k.a they are came from same entity class)? - //this maybe the root entity graph or a sub graph. + attributeMapStack.addLast( buildAttributeNodeMap() ); super.startingEntity( entityDefinition ); } @@ -143,6 +143,12 @@ public abstract class AbstractEntityGraphVisitationStrategy return attributeNodeImplementorMap; } + @Override + public void finishingEntity(final EntityDefinition entityDefinition) { + attributeMapStack.removeLast(); + super.finishingEntity( entityDefinition ); + } + /** * I'm using NULL-OBJECT pattern here, for attributes that not existing in the EntityGraph, * a predefined NULL-ATTRIBUTE-NODE is pushed to the stack. @@ -156,12 +162,13 @@ public abstract class AbstractEntityGraphVisitationStrategy */ @Override public boolean startingAttribute(AttributeDefinition attributeDefinition) { + Map attributeMap = attributeMapStack.peekLast(); final String attrName = attributeDefinition.getName(); AttributeNodeImplementor attributeNode = NON_EXIST_ATTRIBUTE_NODE; GraphNodeImplementor subGraphNode = NON_EXIST_SUBGRAPH_NODE; //the attribute is in the EntityGraph, so, let's continue - if ( attributeNodeImplementorMap.containsKey( attrName ) ) { - attributeNode = attributeNodeImplementorMap.get( attrName ); + if ( attributeMap.containsKey( attrName ) ) { + attributeNode = attributeMap.get( attrName ); //here we need to check if there is a subgraph (or sub key graph if it is an indexed attribute ) Map subGraphs = attributeNode.getSubgraphs(); Class javaType = attributeDefinition.getType().getReturnedClass(); @@ -183,45 +190,18 @@ public abstract class AbstractEntityGraphVisitationStrategy super.finishingAttribute( attributeDefinition ); } - @Override - protected boolean handleAssociationAttribute( - final AssociationAttributeDefinition attributeDefinition) { - return super.handleAssociationAttribute( attributeDefinition ); - } - - @Override - protected boolean handleCompositeAttribute( - final AttributeDefinition attributeDefinition) { - return super.handleCompositeAttribute( attributeDefinition ); - } - - - @Override - public void startingComposite(final CompositionDefinition compositionDefinition) { - super.startingComposite( compositionDefinition ); - } - - - @Override - public void finishingComposite(final CompositionDefinition compositionDefinition) { - super.finishingComposite( compositionDefinition ); - } - - - @Override - public void startingCollection(final CollectionDefinition collectionDefinition) { - super.startingCollection( collectionDefinition ); - } - - @Override - public void finishingCollection(final CollectionDefinition collectionDefinition) { - super.finishingCollection( collectionDefinition ); - } - @Override public void startingCollectionElements( final CollectionElementDefinition elementDefinition) { + AttributeNodeImplementor attributeNode = attributeStack.peekLast(); + GraphNodeImplementor subGraphNode = NON_EXIST_SUBGRAPH_NODE; + Map subGraphs = attributeNode.getSubgraphs(); + Class javaType = elementDefinition.getType().getReturnedClass(); + if ( !subGraphs.isEmpty() && subGraphs.containsKey( javaType ) ) { + subGraphNode = (GraphNodeImplementor) subGraphs.get( javaType ); + } + graphStack.addLast( subGraphNode ); super.startingCollectionElements( elementDefinition ); } @@ -229,6 +209,7 @@ public abstract class AbstractEntityGraphVisitationStrategy public void finishingCollectionElements( final CollectionElementDefinition elementDefinition) { super.finishingCollectionElements( elementDefinition ); + graphStack.removeLast(); } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/SubgraphImpl.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/SubgraphImpl.java index 1002af9905..b7ced5591c 100644 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/SubgraphImpl.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/graph/internal/SubgraphImpl.java @@ -122,7 +122,7 @@ public class SubgraphImpl extends AbstractGraphNode implements Subgraph @Override @SuppressWarnings("unchecked") protected Attribute resolveAttribute(String attributeName) { - final Attribute attribute = managedType.getDeclaredAttribute( attributeName ); + final Attribute attribute = managedType.getAttribute( attributeName ); if ( attribute == null ) { throw new IllegalArgumentException( String.format( diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/graphs/Company.java b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/graphs/Company.java new file mode 100644 index 0000000000..3ab98c0c9b --- /dev/null +++ b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/graphs/Company.java @@ -0,0 +1,54 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * JBoss, Home of Professional Open Source + * Copyright 2014 Red Hat Inc. and/or its affiliates and other contributors + * as indicated by the @authors tag. All rights reserved. + * See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * 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, v. 2.1. + * This program is distributed in the hope that it will be useful, but WITHOUT A + * 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, + * v.2.1 along with this distribution; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +package org.hibernate.jpa.test.graphs; + +import java.util.HashSet; +import java.util.Set; + +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.OneToMany; +import javax.persistence.OneToOne; + + +/** + * @author Brett Meyer + */ +@Entity +public class Company { + @Id @GeneratedValue + public long id; + + @OneToMany + public Set employees = new HashSet(); + + @OneToOne(fetch = FetchType.LAZY) + public Location location; + + @ElementCollection + public Set markets = new HashSet(); + + @ElementCollection(fetch = FetchType.EAGER) + public Set phoneNumbers = new HashSet(); +} diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/graphs/Employee.java b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/graphs/Employee.java new file mode 100644 index 0000000000..65929d36a3 --- /dev/null +++ b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/graphs/Employee.java @@ -0,0 +1,48 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * JBoss, Home of Professional Open Source + * Copyright 2014 Red Hat Inc. and/or its affiliates and other contributors + * as indicated by the @authors tag. All rights reserved. + * See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * 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, v. 2.1. + * This program is distributed in the hope that it will be useful, but WITHOUT A + * 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, + * v.2.1 along with this distribution; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +package org.hibernate.jpa.test.graphs; + +import java.util.HashSet; +import java.util.Set; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Inheritance; +import javax.persistence.InheritanceType; +import javax.persistence.ManyToMany; + + +/** + * @author Brett Meyer + */ +@Entity +@Inheritance( strategy = InheritanceType.TABLE_PER_CLASS ) +public class Employee { + @Id @GeneratedValue + public long id; + + @ManyToMany + public Set managers = new HashSet(); + + @ManyToMany + public Set friends = new HashSet(); +} diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/graphs/find/FindEntityGraphTests.java b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/graphs/EntityGraphTest.java similarity index 53% rename from hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/graphs/find/FindEntityGraphTests.java rename to hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/graphs/EntityGraphTest.java index a8cf4964b0..fa9db8f6d4 100644 --- a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/graphs/find/FindEntityGraphTests.java +++ b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/graphs/EntityGraphTest.java @@ -21,8 +21,9 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.jpa.test.graphs.find; +package org.hibernate.jpa.test.graphs; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.util.HashMap; @@ -35,36 +36,38 @@ import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.ManyToOne; +import javax.persistence.Subgraph; import org.hibernate.Hibernate; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; +import org.hibernate.testing.TestForIssue; import org.junit.Test; /** * @author Christian Bauer + * @author Brett Meyer */ -public class FindEntityGraphTests extends BaseEntityManagerFunctionalTestCase { +public class EntityGraphTest extends BaseEntityManagerFunctionalTestCase { @Override protected Class[] getAnnotatedClasses() { - return new Class[] { Foo.class, Bar.class, Baz.class }; + return new Class[] { Foo.class, Bar.class, Baz.class, + Company.class, Employee.class, Manager.class, Location.class }; } @Test + @TestForIssue(jiraKey = "HHH-8857") public void loadMultipleAssociations() { EntityManager em = getOrCreateEntityManager(); em.getTransaction().begin(); Bar bar = new Bar(); - bar.name = "bar"; em.persist( bar ); Baz baz = new Baz(); - baz.name = "baz"; em.persist( baz ); Foo foo = new Foo(); - foo.name = "foo"; foo.bar = bar; foo.baz = baz; em.persist( foo ); @@ -90,15 +93,65 @@ public class FindEntityGraphTests extends BaseEntityManagerFunctionalTestCase { em.close(); } + /** + * JPA 2.1 spec: "Add a node to the graph that corresponds to a managed type with inheritance. This allows for + * multiple subclass subgraphs to be defined for this node of the entity graph. Subclass subgraphs will + * automatically include the specified attributes of superclass subgraphs." + */ + @Test + @TestForIssue(jiraKey = "HHH-8640") + public void inheritanceTest() { + EntityManager em = getOrCreateEntityManager(); + em.getTransaction().begin(); + + Manager manager = new Manager(); + em.persist( manager ); + Employee employee = new Employee(); + employee.friends.add( manager ); + employee.managers.add( manager ); + em.persist( employee ); + Company company = new Company(); + company.employees.add( employee ); + company.employees.add( manager ); + em.persist( company ); + + em.getTransaction().commit(); + em.clear(); + + em.getTransaction().begin(); + + EntityGraph entityGraph = em.createEntityGraph( Company.class ); + Subgraph subgraph = entityGraph.addSubgraph( "employees" ); + subgraph.addAttributeNodes( "managers" ); + subgraph.addAttributeNodes( "friends" ); + Subgraph subSubgraph = subgraph.addSubgraph( "managers", Manager.class ); + subSubgraph.addAttributeNodes( "managers" ); + subSubgraph.addAttributeNodes( "friends" ); + + Map properties = new HashMap(); + properties.put( "javax.persistence.loadgraph", entityGraph ); + + Company result = em.find( Company.class, company.id, properties ); + + assertTrue( Hibernate.isInitialized( result ) ); + assertTrue( Hibernate.isInitialized( result.employees ) ); + assertEquals( result.employees.size(), 2 ); + for (Employee resultEmployee : result.employees) { + assertTrue( Hibernate.isInitialized( resultEmployee.managers ) ); + assertTrue( Hibernate.isInitialized( resultEmployee.friends ) ); + } + + em.getTransaction().commit(); + em.close(); + } + @Entity - public static class Foo { + private static class Foo { @Id @GeneratedValue public Integer id; - public String name; - @ManyToOne(fetch = FetchType.LAZY) public Bar bar; @@ -107,23 +160,19 @@ public class FindEntityGraphTests extends BaseEntityManagerFunctionalTestCase { } @Entity - public static class Bar { + private static class Bar { @Id @GeneratedValue - public Integer id; - - public String name; + private Integer id; } @Entity - public static class Baz { + private static class Baz { @Id @GeneratedValue - public Integer id; - - public String name; + private Integer id; } } diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/graphs/Location.java b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/graphs/Location.java new file mode 100644 index 0000000000..4543e605b2 --- /dev/null +++ b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/graphs/Location.java @@ -0,0 +1,38 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * JBoss, Home of Professional Open Source + * Copyright 2014 Red Hat Inc. and/or its affiliates and other contributors + * as indicated by the @authors tag. All rights reserved. + * See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * 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, v. 2.1. + * This program is distributed in the hope that it will be useful, but WITHOUT A + * 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, + * v.2.1 along with this distribution; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +package org.hibernate.jpa.test.graphs; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +/** + * @author Brett Meyer + */ +@Entity +public class Location { + @Id @GeneratedValue + public long id; + + public String address; + + public int zip; +} diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/graphs/Manager.java b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/graphs/Manager.java new file mode 100644 index 0000000000..4b8fc3c284 --- /dev/null +++ b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/graphs/Manager.java @@ -0,0 +1,32 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * JBoss, Home of Professional Open Source + * Copyright 2014 Red Hat Inc. and/or its affiliates and other contributors + * as indicated by the @authors tag. All rights reserved. + * See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * 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, v. 2.1. + * This program is distributed in the hope that it will be useful, but WITHOUT A + * 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, + * v.2.1 along with this distribution; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +package org.hibernate.jpa.test.graphs; + +import javax.persistence.Entity; + + +/** + * @author Brett Meyer + */ +@Entity +public class Manager extends Employee { + +} diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/graphs/Market.java b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/graphs/Market.java new file mode 100644 index 0000000000..7073ee35e8 --- /dev/null +++ b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/graphs/Market.java @@ -0,0 +1,29 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * JBoss, Home of Professional Open Source + * Copyright 2014 Red Hat Inc. and/or its affiliates and other contributors + * as indicated by the @authors tag. All rights reserved. + * See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * 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, v. 2.1. + * This program is distributed in the hope that it will be useful, but WITHOUT A + * 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, + * v.2.1 along with this distribution; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +package org.hibernate.jpa.test.graphs; + + +/** + * @author Brett Meyer + */ +public enum Market { + SERVICES, TECHNOLOGY, INDUSTRIAL; +} diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/graphs/queryhint/QueryHintEntityGraphTest.java b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/graphs/queryhint/QueryHintEntityGraphTest.java index fbd368ad95..8fba61920b 100644 --- a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/graphs/queryhint/QueryHintEntityGraphTest.java +++ b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/graphs/queryhint/QueryHintEntityGraphTest.java @@ -23,27 +23,21 @@ package org.hibernate.jpa.test.graphs.queryhint; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import java.io.Serializable; -import java.util.HashSet; import java.util.Iterator; -import java.util.Set; -import javax.persistence.ElementCollection; -import javax.persistence.Entity; import javax.persistence.EntityGraph; import javax.persistence.EntityManager; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; -import javax.persistence.ManyToMany; -import javax.persistence.OneToMany; -import javax.persistence.OneToOne; import javax.persistence.Query; import javax.persistence.Subgraph; import org.hibernate.Hibernate; import org.hibernate.jpa.QueryHints; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; +import org.hibernate.jpa.test.graphs.Company; +import org.hibernate.jpa.test.graphs.Employee; +import org.hibernate.jpa.test.graphs.Location; +import org.hibernate.jpa.test.graphs.Manager; +import org.hibernate.jpa.test.graphs.Market; import org.junit.Before; import org.junit.Test; @@ -81,10 +75,13 @@ public class QueryHintEntityGraphTest extends BaseEntityManagerFunctionalTestCas entityManager = getOrCreateEntityManager(); entityManager.getTransaction().begin(); - Subgraph subgraph1 = entityGraph.addSubgraph( "employees" ); - subgraph1.addAttributeNodes( "managers" ); - Subgraph subgraph2 = subgraph1.addSubgraph( "managers" ); - subgraph2.addAttributeNodes( "managers" ); + Subgraph subgraph = entityGraph.addSubgraph( "employees" ); + subgraph.addAttributeNodes( "managers" ); + subgraph.addAttributeNodes( "friends" ); + Subgraph subSubgraph = subgraph.addSubgraph( "managers", Manager.class ); + subSubgraph.addAttributeNodes( "managers" ); + subSubgraph.addAttributeNodes( "friends" ); + query = entityManager.createQuery( "from " + Company.class.getName() ); query.setHint( QueryHints.HINT_LOADGRAPH, entityGraph ); company = (Company) query.getSingleResult(); @@ -104,10 +101,14 @@ public class QueryHintEntityGraphTest extends BaseEntityManagerFunctionalTestCas while (employeeItr.hasNext()) { Employee employee = employeeItr.next(); assertTrue( Hibernate.isInitialized( employee.managers ) ); - Iterator managerItr = employee.managers.iterator(); + assertTrue( Hibernate.isInitialized( employee.friends ) ); + // test 1 more level + Iterator managerItr = employee.managers.iterator(); while (managerItr.hasNext()) { foundManager = true; - assertTrue( Hibernate.isInitialized( managerItr.next().managers ) ); + Manager manager = managerItr.next(); + assertTrue( Hibernate.isInitialized( manager.managers ) ); + assertTrue( Hibernate.isInitialized( manager.friends ) ); } } assertTrue(foundManager); @@ -144,16 +145,14 @@ public class QueryHintEntityGraphTest extends BaseEntityManagerFunctionalTestCas EntityManager entityManager = getOrCreateEntityManager(); entityManager.getTransaction().begin(); - Employee manager1 = new Employee(); + Manager manager1 = new Manager(); entityManager.persist( manager1 ); - Employee manager2 = new Employee(); - manager2.managers = new HashSet(); + Manager manager2 = new Manager(); manager2.managers.add( manager1 ); entityManager.persist( manager2 ); Employee employee = new Employee(); - employee.managers = new HashSet(); employee.managers.add( manager1 ); entityManager.persist( employee ); @@ -163,15 +162,12 @@ public class QueryHintEntityGraphTest extends BaseEntityManagerFunctionalTestCas entityManager.persist( location ); Company company = new Company(); - company.employees = new HashSet(); company.employees.add( employee ); company.employees.add( manager1 ); company.employees.add( manager2 ); company.location = location; - company.markets = new HashSet(); company.markets.add( Market.SERVICES ); company.markets.add( Market.TECHNOLOGY ); - company.phoneNumbers = new HashSet(); company.phoneNumbers.add( "012-345-6789" ); company.phoneNumbers.add( "987-654-3210" ); entityManager.persist( company ); @@ -182,49 +178,6 @@ public class QueryHintEntityGraphTest extends BaseEntityManagerFunctionalTestCas @Override protected Class[] getAnnotatedClasses() { - return new Class[] { Company.class, Employee.class, Location.class }; - } - - @Entity - private static class Company implements Serializable { - @Id @GeneratedValue - public long id; - - @OneToMany - public Set employees; - - @OneToOne(fetch = FetchType.LAZY) - public Location location; - - @ElementCollection - public Set markets; - - @ElementCollection(fetch = FetchType.EAGER) - public Set phoneNumbers; - } - - @Entity - private static class Employee { - @Id @GeneratedValue - public long id; - - @ManyToMany - public Set managers; - } - - @Entity - private static class Location { - public Location() { } - - @Id @GeneratedValue - public long id; - - public String address; - - public int zip; - } - - private static enum Market { - SERVICES, TECHNOLOGY, INDUSTRIAL; + return new Class[] { Company.class, Employee.class, Manager.class, Location.class }; } }