diff --git a/hibernate-core/src/main/java/org/hibernate/IdentifierLoadAccess.java b/hibernate-core/src/main/java/org/hibernate/IdentifierLoadAccess.java index 9e40dbb8e76d..ab30b71eb522 100644 --- a/hibernate-core/src/main/java/org/hibernate/IdentifierLoadAccess.java +++ b/hibernate-core/src/main/java/org/hibernate/IdentifierLoadAccess.java @@ -6,8 +6,9 @@ import java.util.Optional; +import jakarta.persistence.EntityGraph; + import org.hibernate.graph.GraphSemantic; -import org.hibernate.graph.RootGraph; /** * Loads an entity by its primary identifier. @@ -76,7 +77,7 @@ public interface IdentifierLoadAccess { * * @since 6.3 */ - default IdentifierLoadAccess withFetchGraph(RootGraph graph) { + default IdentifierLoadAccess withFetchGraph(EntityGraph graph) { return with( graph, GraphSemantic.FETCH ); } @@ -87,7 +88,7 @@ default IdentifierLoadAccess withFetchGraph(RootGraph graph) { * * @since 6.3 */ - default IdentifierLoadAccess withLoadGraph(RootGraph graph) { + default IdentifierLoadAccess withLoadGraph(EntityGraph graph) { return with( graph, GraphSemantic.LOAD ); } @@ -95,7 +96,7 @@ default IdentifierLoadAccess withLoadGraph(RootGraph graph) { * @deprecated use {@link #withLoadGraph} */ @Deprecated(since = "6.3") - default IdentifierLoadAccess with(RootGraph graph) { + default IdentifierLoadAccess with(EntityGraph graph) { return withLoadGraph( graph ); } @@ -104,7 +105,7 @@ default IdentifierLoadAccess with(RootGraph graph) { * {@linkplain jakarta.persistence.EntityGraph entity graph}, * and how it should be {@linkplain GraphSemantic interpreted}. */ - IdentifierLoadAccess with(RootGraph graph, GraphSemantic semantic); + IdentifierLoadAccess with(EntityGraph graph, GraphSemantic semantic); /** * Customize the associations fetched by specifying a diff --git a/hibernate-core/src/main/java/org/hibernate/MultiIdentifierLoadAccess.java b/hibernate-core/src/main/java/org/hibernate/MultiIdentifierLoadAccess.java index 9dcc83dc83b1..5debe9552c66 100644 --- a/hibernate-core/src/main/java/org/hibernate/MultiIdentifierLoadAccess.java +++ b/hibernate-core/src/main/java/org/hibernate/MultiIdentifierLoadAccess.java @@ -6,8 +6,9 @@ import java.util.List; +import jakarta.persistence.EntityGraph; + import org.hibernate.graph.GraphSemantic; -import org.hibernate.graph.RootGraph; /** * Loads multiple instances of a given entity type at once, by @@ -65,7 +66,7 @@ public interface MultiIdentifierLoadAccess { * * @since 6.3 */ - default MultiIdentifierLoadAccess withFetchGraph(RootGraph graph) { + default MultiIdentifierLoadAccess withFetchGraph(EntityGraph graph) { return with( graph, GraphSemantic.FETCH ); } @@ -76,7 +77,7 @@ default MultiIdentifierLoadAccess withFetchGraph(RootGraph graph) { * * @since 6.3 */ - default MultiIdentifierLoadAccess withLoadGraph(RootGraph graph) { + default MultiIdentifierLoadAccess withLoadGraph(EntityGraph graph) { return with( graph, GraphSemantic.LOAD ); } @@ -84,7 +85,7 @@ default MultiIdentifierLoadAccess withLoadGraph(RootGraph graph) { * @deprecated use {@link #withLoadGraph} */ @Deprecated(since = "6.3") - default MultiIdentifierLoadAccess with(RootGraph graph) { + default MultiIdentifierLoadAccess with(EntityGraph graph) { return with( graph, GraphSemantic.LOAD ); } @@ -93,7 +94,7 @@ default MultiIdentifierLoadAccess with(RootGraph graph) { * {@linkplain jakarta.persistence.EntityGraph entity graph}, * and how it should be {@linkplain GraphSemantic interpreted}. */ - MultiIdentifierLoadAccess with(RootGraph graph, GraphSemantic semantic); + MultiIdentifierLoadAccess with(EntityGraph graph, GraphSemantic semantic); /** * Customize the associations fetched by specifying a diff --git a/hibernate-core/src/main/java/org/hibernate/NaturalIdLoadAccess.java b/hibernate-core/src/main/java/org/hibernate/NaturalIdLoadAccess.java index 8150d7aa21b1..bb2a9c09a1e8 100644 --- a/hibernate-core/src/main/java/org/hibernate/NaturalIdLoadAccess.java +++ b/hibernate-core/src/main/java/org/hibernate/NaturalIdLoadAccess.java @@ -4,9 +4,10 @@ */ package org.hibernate; +import jakarta.persistence.EntityGraph; + import jakarta.persistence.metamodel.SingularAttribute; import org.hibernate.graph.GraphSemantic; -import org.hibernate.graph.RootGraph; import java.util.Map; import java.util.Optional; @@ -51,7 +52,7 @@ public interface NaturalIdLoadAccess { * * @since 6.3 */ - default NaturalIdLoadAccess withFetchGraph(RootGraph graph) { + default NaturalIdLoadAccess withFetchGraph(EntityGraph graph) { return with( graph, GraphSemantic.FETCH ); } @@ -62,7 +63,7 @@ default NaturalIdLoadAccess withFetchGraph(RootGraph graph) { * * @since 6.3 */ - default NaturalIdLoadAccess withLoadGraph(RootGraph graph) { + default NaturalIdLoadAccess withLoadGraph(EntityGraph graph) { return with( graph, GraphSemantic.LOAD ); } @@ -73,7 +74,7 @@ default NaturalIdLoadAccess withLoadGraph(RootGraph graph) { * * @since 6.3 */ - NaturalIdLoadAccess with(RootGraph graph, GraphSemantic semantic); + NaturalIdLoadAccess with(EntityGraph graph, GraphSemantic semantic); /** * Customize the associations fetched by specifying a diff --git a/hibernate-core/src/main/java/org/hibernate/NaturalIdMultiLoadAccess.java b/hibernate-core/src/main/java/org/hibernate/NaturalIdMultiLoadAccess.java index bf00203bfaaf..dd5d329e8130 100644 --- a/hibernate-core/src/main/java/org/hibernate/NaturalIdMultiLoadAccess.java +++ b/hibernate-core/src/main/java/org/hibernate/NaturalIdMultiLoadAccess.java @@ -4,8 +4,9 @@ */ package org.hibernate; +import jakarta.persistence.EntityGraph; + import org.hibernate.graph.GraphSemantic; -import org.hibernate.graph.RootGraph; import java.util.List; @@ -61,7 +62,7 @@ public interface NaturalIdMultiLoadAccess { * * @since 6.3 */ - default NaturalIdMultiLoadAccess withFetchGraph(RootGraph graph) { + default NaturalIdMultiLoadAccess withFetchGraph(EntityGraph graph) { return with( graph, GraphSemantic.FETCH ); } @@ -72,7 +73,7 @@ default NaturalIdMultiLoadAccess withFetchGraph(RootGraph graph) { * * @since 6.3 */ - default NaturalIdMultiLoadAccess withLoadGraph(RootGraph graph) { + default NaturalIdMultiLoadAccess withLoadGraph(EntityGraph graph) { return with( graph, GraphSemantic.LOAD ); } @@ -80,7 +81,7 @@ default NaturalIdMultiLoadAccess withLoadGraph(RootGraph graph) { * @deprecated use {@link #withLoadGraph} */ @Deprecated(since = "6.3") - default NaturalIdMultiLoadAccess with(RootGraph graph) { + default NaturalIdMultiLoadAccess with(EntityGraph graph) { return with( graph, GraphSemantic.LOAD ); } @@ -89,7 +90,7 @@ default NaturalIdMultiLoadAccess with(RootGraph graph) { * {@linkplain jakarta.persistence.EntityGraph entity graph}, * and how it should be {@linkplain GraphSemantic interpreted}. */ - NaturalIdMultiLoadAccess with(RootGraph graph, GraphSemantic semantic); + NaturalIdMultiLoadAccess with(EntityGraph graph, GraphSemantic semantic); /** * Specify a batch size, that is, how many entities should be diff --git a/hibernate-core/src/main/java/org/hibernate/Session.java b/hibernate-core/src/main/java/org/hibernate/Session.java index cf360206195c..e345b9f90039 100644 --- a/hibernate-core/src/main/java/org/hibernate/Session.java +++ b/hibernate-core/src/main/java/org/hibernate/Session.java @@ -597,6 +597,46 @@ public interface Session extends SharedSessionContract, EntityManager { */ List findMultiple(Class entityType, List ids, FindOption... options); + /** + * Return the persistent instances of the root entity of the given {@link EntityGraph} + * with the given identifiers as a list, fetching the associations specified by the + * graph, which is interpreted as a {@linkplain org.hibernate.graph.GraphSemantic#LOAD + * load graph}. The position of an instance in the returned list matches the position of + * its identifier in the given list of identifiers, and the returned list contains a null + * value if there is no persistent instance matching a given identifier. If an instance + * is already associated with the session, that instance is returned. This method never + * returns an uninitialized instance. + *

+ * Every object returned by {@code findMultiple()} is either an unproxied instance of the + * given entity class, or a fully-fetched proxy object. + *

+ * This method accepts {@link BatchSize} as an option, allowing control over the number of + * records retrieved in a single database request. The performance impact of setting a batch + * size depends on whether a SQL array may be used to pass the list of identifiers to the + * database: + *

    + *
  • for databases which {@linkplain org.hibernate.dialect.Dialect#supportsStandardArrays + * support standard SQL arrays}, a smaller batch size might be extremely inefficient + * compared to a very large batch size or no batching at all, but + *
  • on the other hand, for databases with no SQL array type, a large batch size results + * in long SQL statements with many JDBC parameters. + *
+ *

+ * For more advanced cases, use {@link #byMultipleIds(Class)}, which returns an instance of + * {@link MultiIdentifierLoadAccess}. + * + * @param entityGraph the entity graph interpreted as a load graph + * @param ids the list of identifiers + * @param options options, if any + * + * @return an ordered list of persistent instances, with null elements representing missing + * entities, whose positions in the list match the positions of their ids in the + * given list of identifiers + * @see #byMultipleIds(Class) + * @since 7.0 + */ + List findMultiple(EntityGraph entityGraph, List ids, FindOption... options); + /** * Read the persistent state associated with the given identifier into the given * transient instance. diff --git a/hibernate-core/src/main/java/org/hibernate/SimpleNaturalIdLoadAccess.java b/hibernate-core/src/main/java/org/hibernate/SimpleNaturalIdLoadAccess.java index 652eabf0c7f1..4b3ad6c3d77b 100644 --- a/hibernate-core/src/main/java/org/hibernate/SimpleNaturalIdLoadAccess.java +++ b/hibernate-core/src/main/java/org/hibernate/SimpleNaturalIdLoadAccess.java @@ -4,8 +4,9 @@ */ package org.hibernate; +import jakarta.persistence.EntityGraph; + import org.hibernate.graph.GraphSemantic; -import org.hibernate.graph.RootGraph; import java.util.Optional; @@ -45,7 +46,7 @@ public interface SimpleNaturalIdLoadAccess { * * @since 6.3 */ - default SimpleNaturalIdLoadAccess withFetchGraph(RootGraph graph) { + default SimpleNaturalIdLoadAccess withFetchGraph(EntityGraph graph) { return with( graph, GraphSemantic.FETCH ); } @@ -56,7 +57,7 @@ default SimpleNaturalIdLoadAccess withFetchGraph(RootGraph graph) { * * @since 6.3 */ - default SimpleNaturalIdLoadAccess withLoadGraph(RootGraph graph) { + default SimpleNaturalIdLoadAccess withLoadGraph(EntityGraph graph) { return with( graph, GraphSemantic.LOAD ); } @@ -67,7 +68,7 @@ default SimpleNaturalIdLoadAccess withLoadGraph(RootGraph graph) { * * @since 6.3 */ - SimpleNaturalIdLoadAccess with(RootGraph graph, GraphSemantic semantic); + SimpleNaturalIdLoadAccess with(EntityGraph graph, GraphSemantic semantic); /** * Customize the associations fetched by specifying a diff --git a/hibernate-core/src/main/java/org/hibernate/StatelessSession.java b/hibernate-core/src/main/java/org/hibernate/StatelessSession.java index cd32aa8e401d..9281282a7419 100644 --- a/hibernate-core/src/main/java/org/hibernate/StatelessSession.java +++ b/hibernate-core/src/main/java/org/hibernate/StatelessSession.java @@ -372,6 +372,45 @@ public interface StatelessSession extends SharedSessionContract { */ List getMultiple(Class entityClass, List ids, LockMode lockMode); + /** + * Retrieve multiple rows, returning instances of the root + * entity of the given {@link EntityGraph} with the fetched + * associations specified by the graph, in a list where the + * position of an instance in the list matches the position + * of its identifier in the given array, and the list + * contains a null value if there is no persistent instance + * matching a given identifier. + * + * @param entityGraph The {@link EntityGraph}, interpreted as a + * {@linkplain org.hibernate.graph.GraphSemantic#LOAD load graph} + * @param graphSemantic a {@link GraphSemantic} specifying + * how the graph should be interpreted + * @param ids The ids of the entities to retrieve + * @return an ordered list of detached entity instances, with + * null elements representing missing entities + * @since 7.0 + */ + List getMultiple(EntityGraph entityGraph, List ids); + + /** + * Retrieve multiple rows, returning instances of the root + * entity of the given {@link EntityGraph} with the fetched + * associations specified by the graph, in a list where the + * position of an instance in the list matches the position + * of its identifier in the given array, and the list + * contains a null value if there is no persistent instance + * matching a given identifier. + * + * @param entityGraph The {@link EntityGraph} + * @param graphSemantic a {@link GraphSemantic} specifying + * how the graph should be interpreted + * @param ids The ids of the entities to retrieve + * @return an ordered list of detached entity instances, with + * null elements representing missing entities + * @since 7.0 + */ + List getMultiple(EntityGraph entityGraph, GraphSemantic graphSemantic, List ids); + /** * Refresh the entity instance state from the database. * diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java index 05a70ec97e8d..578746ce4c83 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java @@ -967,6 +967,11 @@ public List findMultiple(Class entityType, List ids, FindOption... return delegate.findMultiple( entityType, ids, options ); } + @Override + public List findMultiple(EntityGraph entityGraph, List ids, FindOption... options) { + return delegate.findMultiple( entityGraph, ids, options ); + } + @Override public T get(Class theClass, Object id) { return delegate.get( theClass, id ); diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionLazyDelegator.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionLazyDelegator.java index 9001be8ccac0..cdc8d2c8ddd5 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionLazyDelegator.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionLazyDelegator.java @@ -271,6 +271,11 @@ public List findMultiple(Class entityType, List ids, FindOption... return this.lazySession.get().findMultiple( entityType, ids, options ); } + @Override + public List findMultiple(EntityGraph entityGraph, List ids, FindOption... options) { + return this.lazySession.get().findMultiple( entityGraph, ids, options ); + } + @Override public T get(Class entityType, Object id) { return this.lazySession.get().get( entityType, id ); diff --git a/hibernate-core/src/main/java/org/hibernate/internal/MultiIdentifierLoadAccessImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/MultiIdentifierLoadAccessImpl.java index ffab763a7de9..bba064dd9b6d 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/MultiIdentifierLoadAccessImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/MultiIdentifierLoadAccessImpl.java @@ -9,6 +9,8 @@ import java.util.Set; import java.util.function.Supplier; +import jakarta.persistence.EntityGraph; + import org.hibernate.CacheMode; import org.hibernate.LockOptions; import org.hibernate.MultiIdentifierLoadAccess; @@ -18,7 +20,6 @@ import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.graph.GraphSemantic; -import org.hibernate.graph.RootGraph; import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.loader.ast.spi.MultiIdLoadOptions; @@ -76,7 +77,7 @@ public MultiIdentifierLoadAccess withReadOnly(boolean readOnly) { } @Override - public MultiIdentifierLoadAccess with(RootGraph graph, GraphSemantic semantic) { + public MultiIdentifierLoadAccess with(EntityGraph graph, GraphSemantic semantic) { this.rootGraph = (RootGraphImplementor) graph; this.graphSemantic = semantic; return this; diff --git a/hibernate-core/src/main/java/org/hibernate/internal/NaturalIdMultiLoadAccessStandard.java b/hibernate-core/src/main/java/org/hibernate/internal/NaturalIdMultiLoadAccessStandard.java index 640f23a504ec..5b28a0f480cb 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/NaturalIdMultiLoadAccessStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/NaturalIdMultiLoadAccessStandard.java @@ -6,6 +6,8 @@ import java.util.List; +import jakarta.persistence.EntityGraph; + import org.hibernate.CacheMode; import org.hibernate.LockOptions; import org.hibernate.NaturalIdMultiLoadAccess; @@ -13,7 +15,6 @@ import org.hibernate.engine.spi.LoadQueryInfluencers; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.graph.GraphSemantic; -import org.hibernate.graph.RootGraph; import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.loader.ast.spi.MultiNaturalIdLoadOptions; import org.hibernate.persister.entity.EntityPersister; @@ -55,7 +56,7 @@ public NaturalIdMultiLoadAccess with(CacheMode cacheMode) { } @Override - public NaturalIdMultiLoadAccess with(RootGraph graph, GraphSemantic semantic) { + public NaturalIdMultiLoadAccess with(EntityGraph graph, GraphSemantic semantic) { this.rootGraph = (RootGraphImplementor) graph; this.graphSemantic = semantic; return this; diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java index 3d8c03bd80b2..5f2dabfda8fe 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java @@ -1051,6 +1051,16 @@ public List findMultiple(Class entityType, List ids, FindOption... return loadAccess.multiLoad( ids ); } + @Override + public List findMultiple(EntityGraph entityGraph, List ids, FindOption... options) { + final RootGraph rootGraph = (RootGraph) entityGraph; + final MultiIdentifierLoadAccess loadAccess = + byMultipleIds( rootGraph.getGraphedType().getJavaType() ); + loadAccess.withLoadGraph( rootGraph ); + setMultiIdentifierLoadAccessOptions( options, loadAccess ); + return loadAccess.multiLoad( ids ); + } + @Override public T get(Class entityClass, Object id) { return byId( entityClass ).load( id ); diff --git a/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java index b6c2e5c62b86..5369ac021434 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java @@ -801,11 +801,39 @@ public List getMultiple(Class entityClass, List ids, LockMode lockM } final EntityPersister persister = requireEntityPersister( entityClass.getName() ); - final List results = persister.multiLoad( ids.toArray(), this, new MultiLoadOptions(lockMode) ); //noinspection unchecked return (List) results; } + @Override + public List getMultiple(EntityGraph entityGraph, List ids) { + return getMultiple( entityGraph, GraphSemantic.LOAD, ids ); + } + + @Override + public List getMultiple(EntityGraph entityGraph, GraphSemantic graphSemantic, List ids) { + for ( Object id : ids ) { + if ( id == null ) { + throw new IllegalArgumentException( "Null id" ); + } + } + + final RootGraphImplementor rootGraph = (RootGraphImplementor) entityGraph; + + final EffectiveEntityGraph effectiveEntityGraph = + getLoadQueryInfluencers().getEffectiveEntityGraph(); + effectiveEntityGraph.applyGraph( rootGraph, graphSemantic ); + + try { + final EntityPersister persister = requireEntityPersister( rootGraph.getGraphedType().getTypeName() ); + final List results = persister.multiLoad( ids.toArray(), this, MULTI_ID_LOAD_OPTIONS ); + //noinspection unchecked + return (List) results; + } + finally { + effectiveEntityGraph.clear(); + } + } @Override public List getMultiple(Class entityClass, List ids) { @@ -816,7 +844,6 @@ public List getMultiple(Class entityClass, List ids) { } final EntityPersister persister = requireEntityPersister( entityClass.getName() ); - final List results = persister.multiLoad( ids.toArray(), this, MULTI_ID_LOAD_OPTIONS ); //noinspection unchecked return (List) results; diff --git a/hibernate-core/src/main/java/org/hibernate/loader/internal/BaseNaturalIdLoadAccessImpl.java b/hibernate-core/src/main/java/org/hibernate/loader/internal/BaseNaturalIdLoadAccessImpl.java index 576e63faf19c..cca75ba55e74 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/internal/BaseNaturalIdLoadAccessImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/internal/BaseNaturalIdLoadAccessImpl.java @@ -7,6 +7,8 @@ import java.util.HashSet; import java.util.Set; +import jakarta.persistence.EntityGraph; + import org.hibernate.HibernateException; import org.hibernate.IdentifierLoadAccess; import org.hibernate.LockOptions; @@ -18,7 +20,6 @@ import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.spi.Status; import org.hibernate.graph.GraphSemantic; -import org.hibernate.graph.RootGraph; import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.loader.LoaderLogging; import org.hibernate.loader.ast.spi.NaturalIdLoadOptions; @@ -63,7 +64,7 @@ public LockOptions getLockOptions() { return lockOptions; } - public Object with(RootGraph graph, GraphSemantic semantic) { + public Object with(EntityGraph graph, GraphSemantic semantic) { this.rootGraph = (RootGraphImplementor) graph; this.graphSemantic = semantic; return this; diff --git a/hibernate-core/src/main/java/org/hibernate/loader/internal/IdentifierLoadAccessImpl.java b/hibernate-core/src/main/java/org/hibernate/loader/internal/IdentifierLoadAccessImpl.java index 0dde4abaf774..81270f40ce68 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/internal/IdentifierLoadAccessImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/internal/IdentifierLoadAccessImpl.java @@ -9,6 +9,8 @@ import java.util.Set; import java.util.function.Supplier; +import jakarta.persistence.EntityGraph; + import org.hibernate.CacheMode; import org.hibernate.IdentifierLoadAccess; import org.hibernate.LockOptions; @@ -23,7 +25,6 @@ import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.event.spi.LoadEventListener; import org.hibernate.graph.GraphSemantic; -import org.hibernate.graph.RootGraph; import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.persister.entity.EntityPersister; @@ -75,7 +76,7 @@ public IdentifierLoadAccess withReadOnly(boolean readOnly) { } @Override - public IdentifierLoadAccess with(RootGraph graph, GraphSemantic semantic) { + public IdentifierLoadAccess with(EntityGraph graph, GraphSemantic semantic) { this.rootGraph = (RootGraphImplementor) graph; this.graphSemantic = semantic; return this; diff --git a/hibernate-core/src/main/java/org/hibernate/loader/internal/NaturalIdLoadAccessImpl.java b/hibernate-core/src/main/java/org/hibernate/loader/internal/NaturalIdLoadAccessImpl.java index 0026bc40e87f..af719fb65031 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/internal/NaturalIdLoadAccessImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/internal/NaturalIdLoadAccessImpl.java @@ -8,11 +8,12 @@ import java.util.Map; import java.util.Optional; +import jakarta.persistence.EntityGraph; import jakarta.persistence.metamodel.SingularAttribute; + import org.hibernate.LockOptions; import org.hibernate.NaturalIdLoadAccess; import org.hibernate.graph.GraphSemantic; -import org.hibernate.graph.RootGraph; import org.hibernate.metamodel.mapping.EntityMappingType; /** @@ -70,7 +71,7 @@ public Optional loadOptional() { } @Override - public NaturalIdLoadAccess with(RootGraph graph, GraphSemantic semantic) { + public NaturalIdLoadAccess with(EntityGraph graph, GraphSemantic semantic) { super.with( graph, semantic ); return this; } diff --git a/hibernate-core/src/main/java/org/hibernate/loader/internal/SimpleNaturalIdLoadAccessImpl.java b/hibernate-core/src/main/java/org/hibernate/loader/internal/SimpleNaturalIdLoadAccessImpl.java index a98eef6e9fe6..0c3e5b62a078 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/internal/SimpleNaturalIdLoadAccessImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/internal/SimpleNaturalIdLoadAccessImpl.java @@ -9,11 +9,12 @@ import java.util.Map; import java.util.Optional; +import jakarta.persistence.EntityGraph; + import org.hibernate.HibernateException; import org.hibernate.LockOptions; import org.hibernate.SimpleNaturalIdLoadAccess; import org.hibernate.graph.GraphSemantic; -import org.hibernate.graph.RootGraph; import org.hibernate.loader.LoaderLogging; import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.internal.SimpleNaturalIdMapping; @@ -105,13 +106,13 @@ public Optional loadOptional(Object naturalIdValue) { } @Override - public SimpleNaturalIdLoadAccess with(RootGraph graph, GraphSemantic semantic) { + public SimpleNaturalIdLoadAccess with(EntityGraph graph, GraphSemantic semantic) { super.with( graph, semantic ); return this; } @Override - public SimpleNaturalIdLoadAccess withLoadGraph(RootGraph graph) { + public SimpleNaturalIdLoadAccess withLoadGraph(EntityGraph graph) { return SimpleNaturalIdLoadAccess.super.withLoadGraph(graph); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/loading/multiLoad/FindMultipleEntityGraphTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/loading/multiLoad/FindMultipleEntityGraphTest.java new file mode 100644 index 000000000000..4bf66471097b --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/loading/multiLoad/FindMultipleEntityGraphTest.java @@ -0,0 +1,80 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.loading.multiLoad; + +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import org.hibernate.Hibernate; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@SessionFactory +@DomainModel(annotatedClasses = {FindMultipleEntityGraphTest.Record.class, FindMultipleEntityGraphTest.Owner.class}) +public class FindMultipleEntityGraphTest { + @Test void test(SessionFactoryScope scope) { + var graph = scope.getSessionFactory().createEntityGraph(Record.class); + graph.addAttributeNode("owner"); + scope.inTransaction(s-> { + Owner gavin = new Owner("gavin"); + s.persist(gavin); + s.persist(new Record(123L,gavin,"hello earth")); + s.persist(new Record(456L,gavin,"hello mars")); + }); + scope.inTransaction(s-> { + List all = s.findMultiple(Record.class, List.of(456L, 123L, 2L)); + assertEquals("hello mars",all.get(0).message); + assertEquals("hello earth",all.get(1).message); + assertNull(all.get(2)); + assertFalse(Hibernate.isInitialized(all.get(0).owner)); + assertFalse(Hibernate.isInitialized(all.get(1).owner)); + }); + scope.inTransaction(s-> { + List all = s.findMultiple(graph, List.of(456L, 123L)); + assertEquals("hello mars",all.get(0).message); + assertEquals("hello earth",all.get(1).message); + assertTrue(Hibernate.isInitialized(all.get(0).owner)); + assertTrue(Hibernate.isInitialized(all.get(1).owner)); + }); + } + @Entity + static class Record { + @Id Long id; + String message; + + @ManyToOne(fetch = FetchType.LAZY) + Owner owner; + + Record(Long id, Owner owner, String message) { + this.id = id; + this.owner = owner; + this.message = message; + } + + Record() { + } + } + @Entity + static class Owner { + @Id String name; + + Owner(String name) { + this.name = name; + } + + Owner() { + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/loading/multiLoad/GetMultipleEntityGraphTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/loading/multiLoad/GetMultipleEntityGraphTest.java new file mode 100644 index 000000000000..751473f13941 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/loading/multiLoad/GetMultipleEntityGraphTest.java @@ -0,0 +1,80 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.loading.multiLoad; + +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import org.hibernate.Hibernate; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@SessionFactory +@DomainModel(annotatedClasses = {GetMultipleEntityGraphTest.Record.class, GetMultipleEntityGraphTest.Owner.class}) +public class GetMultipleEntityGraphTest { + @Test void test(SessionFactoryScope scope) { + var graph = scope.getSessionFactory().createEntityGraph(Record.class); + graph.addAttributeNode("owner"); + scope.inStatelessTransaction(s-> { + Owner gavin = new Owner("gavin"); + s.insert(gavin); + s.insert(new Record(123L,gavin,"hello earth")); + s.insert(new Record(456L,gavin,"hello mars")); + }); + scope.inStatelessTransaction(s-> { + List all = s.getMultiple(Record.class, List.of(456L, 123L, 2L)); + assertEquals("hello mars",all.get(0).message); + assertEquals("hello earth",all.get(1).message); + assertNull(all.get(2)); + assertFalse(Hibernate.isInitialized(all.get(0).owner)); + assertFalse(Hibernate.isInitialized(all.get(1).owner)); + }); + scope.inStatelessTransaction(s-> { + List all = s.getMultiple(graph, List.of(456L, 123L)); + assertEquals("hello mars",all.get(0).message); + assertEquals("hello earth",all.get(1).message); + assertTrue(Hibernate.isInitialized(all.get(0).owner)); + assertTrue(Hibernate.isInitialized(all.get(1).owner)); + }); + } + @Entity + static class Record { + @Id Long id; + String message; + + @ManyToOne(fetch = FetchType.LAZY) + Owner owner; + + Record(Long id, Owner owner, String message) { + this.id = id; + this.owner = owner; + this.message = message; + } + + Record() { + } + } + @Entity + static class Owner { + @Id String name; + + Owner(String name) { + this.name = name; + } + + Owner() { + } + } +}