HHH-8903 bi-directional fetches in entity graphs
This commit is contained in:
parent
fef6c5394a
commit
f815f70f51
|
@ -32,4 +32,5 @@ import javax.persistence.AttributeNode;
|
|||
public interface GraphNodeImplementor {
|
||||
List<AttributeNodeImplementor<?>> attributeImplementorNodes();
|
||||
List<AttributeNode<?>> attributeNodes();
|
||||
boolean containsAttribute(String name);
|
||||
}
|
||||
|
|
|
@ -45,9 +45,12 @@ import org.hibernate.graph.spi.AttributeNodeImplementor;
|
|||
import org.hibernate.graph.spi.GraphNodeImplementor;
|
||||
import org.hibernate.internal.CoreLogging;
|
||||
import org.hibernate.loader.plan.spi.EntityReturn;
|
||||
import org.hibernate.loader.plan.spi.FetchSource;
|
||||
import org.hibernate.loader.plan.spi.LoadPlan;
|
||||
import org.hibernate.loader.plan.spi.Return;
|
||||
import org.hibernate.persister.entity.Joinable;
|
||||
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
|
||||
import org.hibernate.persister.walking.spi.AssociationKey;
|
||||
import org.hibernate.persister.walking.spi.AttributeDefinition;
|
||||
import org.hibernate.persister.walking.spi.CollectionElementDefinition;
|
||||
import org.hibernate.persister.walking.spi.CollectionIndexDefinition;
|
||||
|
@ -330,5 +333,30 @@ public abstract class AbstractEntityGraphVisitationStrategy
|
|||
public List<AttributeNode<?>> attributeNodes() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAttribute(String name) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void foundCircularAssociation(AssociationAttributeDefinition attributeDefinition) {
|
||||
final FetchStrategy fetchStrategy = determineFetchStrategy( attributeDefinition );
|
||||
if ( fetchStrategy.getStyle() != FetchStyle.JOIN ) {
|
||||
return; // nothing to do
|
||||
}
|
||||
|
||||
// Bi-directional association & the owning side was already visited. If the current attribute node refers
|
||||
// to it, fetch.
|
||||
// ENTITY nature handled by super.
|
||||
final GraphNodeImplementor graphNode = graphStack.peekLast();
|
||||
if ( attributeDefinition.getAssociationNature() == AssociationAttributeDefinition.AssociationNature.COLLECTION
|
||||
&& ! graphNode.equals( NON_EXIST_SUBGRAPH_NODE)
|
||||
&& graphNode.containsAttribute( attributeDefinition.getName() )) {
|
||||
currentSource().buildCollectionAttributeFetch( attributeDefinition, fetchStrategy );
|
||||
}
|
||||
|
||||
super.foundCircularAssociation( attributeDefinition );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -138,7 +138,7 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
|
|||
return last;
|
||||
}
|
||||
|
||||
private ExpandingFetchSource currentSource() {
|
||||
protected ExpandingFetchSource currentSource() {
|
||||
return fetchSourceStack.peekFirst();
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ import java.util.Collections;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.AttributeNode;
|
||||
import javax.persistence.metamodel.Attribute;
|
||||
|
||||
|
@ -36,7 +37,6 @@ import org.hibernate.graph.spi.GraphNodeImplementor;
|
|||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.jpa.HibernateEntityManagerFactory;
|
||||
import org.hibernate.jpa.spi.HibernateEntityManagerFactoryAware;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
/**
|
||||
|
@ -44,7 +44,7 @@ import org.jboss.logging.Logger;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract class AbstractGraphNode<T> implements GraphNodeImplementor, HibernateEntityManagerFactoryAware{
|
||||
public abstract class AbstractGraphNode<T> implements GraphNodeImplementor, HibernateEntityManagerFactoryAware {
|
||||
private static final Logger log = Logger.getLogger( AbstractGraphNode.class );
|
||||
|
||||
private final HibernateEntityManagerFactory entityManagerFactory;
|
||||
|
@ -200,4 +200,9 @@ public abstract class AbstractGraphNode<T> implements GraphNodeImplementor, Hibe
|
|||
public <X> SubgraphImpl<X> addKeySubgraph(String attributeName, Class<X> type) {
|
||||
return addAttribute( attributeName ).makeKeySubgraph( type );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAttribute(String name) {
|
||||
return attributeNodeMap != null && attributeNodeMap.containsKey( name );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -136,10 +136,14 @@ public class EntityGraphTest extends BaseEntityManagerFunctionalTestCase {
|
|||
|
||||
Bar bar = new Bar();
|
||||
em.persist( bar );
|
||||
Baz baz = new Baz();
|
||||
em.persist( baz );
|
||||
|
||||
Foo foo = new Foo();
|
||||
foo.bar = bar;
|
||||
foo.baz = baz;
|
||||
bar.foos.add(foo);
|
||||
baz.foos.add(foo);
|
||||
em.persist( foo );
|
||||
|
||||
em.getTransaction().commit();
|
||||
|
@ -149,7 +153,8 @@ public class EntityGraphTest extends BaseEntityManagerFunctionalTestCase {
|
|||
|
||||
EntityGraph<Foo> fooGraph = em.createEntityGraph( Foo.class );
|
||||
fooGraph.addAttributeNodes("bar");
|
||||
Subgraph barGraph = fooGraph.addSubgraph("bar");
|
||||
fooGraph.addAttributeNodes("baz");
|
||||
Subgraph<Bar> barGraph = fooGraph.addSubgraph("bar", Bar.class);
|
||||
barGraph.addAttributeNodes("foos");
|
||||
|
||||
Map<String, Object> properties = new HashMap<String, Object>();
|
||||
|
@ -160,6 +165,9 @@ public class EntityGraphTest extends BaseEntityManagerFunctionalTestCase {
|
|||
assertTrue( Hibernate.isInitialized( result ) );
|
||||
assertTrue( Hibernate.isInitialized( result.bar ) );
|
||||
assertTrue( Hibernate.isInitialized( result.bar.foos) );
|
||||
assertTrue( Hibernate.isInitialized( result.baz ) );
|
||||
// sanity check -- ensure the only bi-directional fetch was the one identified by the graph
|
||||
assertFalse( Hibernate.isInitialized( result.baz.foos) );
|
||||
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
|
@ -249,6 +257,9 @@ public class EntityGraphTest extends BaseEntityManagerFunctionalTestCase {
|
|||
@GeneratedValue
|
||||
public Integer id;
|
||||
|
||||
@OneToMany(mappedBy = "bar")
|
||||
public Set<Foo> foos = new HashSet<Foo>();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue