graph, GraphSemantic semantic);
/**
- * Return the persistent instance with the given identifier, assuming that the instance exists. This method
- * might return a proxied instance that is initialized on-demand, when a non-identifier method is accessed.
+ * Return the persistent instance with the given identifier, assuming
+ * that the instance exists. This method might return a proxied instance
+ * that is initialized on-demand, when a non-identifier method is accessed.
*
- * You should not use this method to determine if an instance exists; to check for existence, use {@link #load}
- * instead. Use this only to retrieve an instance that you assume exists, where non-existence would be an
- * actual error.
+ * You should not use this method to determine if an instance exists;
+ * to check for existence, use {@link #load} instead. Use this only to
+ * retrieve an instance that you assume exists, where non-existence would
+ * be an actual error.
*
* @param id The identifier for which to obtain a reference
*
@@ -76,9 +105,10 @@ public interface IdentifierLoadAccess {
T getReference(Object id);
/**
- * Return the persistent instance with the given identifier, or null if there is no such persistent instance.
- * If the instance is already associated with the session, return that instance, initializing it if needed. This
- * method never returns an uninitialized instance.
+ * Return the persistent instance with the given identifier, or null
+ * if there is no such persistent instance. If the instance is already
+ * associated with the session, return that instance, initializing it
+ * if needed. This method never returns an uninitialized instance.
*
* @param id The identifier
*
@@ -87,12 +117,12 @@ public interface IdentifierLoadAccess {
T load(Object id);
/**
- * Same semantic as {@link #load} except that here {@link Optional} is returned to
- * handle nullability.
+ * Just like {@link #load}, except that here an {@link Optional} is
+ * returned.
*
* @param id The identifier
*
- * @return The persistent instance, if one, wrapped in Optional
+ * @return The persistent instance, if any, as an {@link Optional}
*/
Optional loadOptional(Object id);
}
diff --git a/hibernate-core/src/main/java/org/hibernate/MultiIdentifierLoadAccess.java b/hibernate-core/src/main/java/org/hibernate/MultiIdentifierLoadAccess.java
index ae80d7116c..3e1456e11a 100644
--- a/hibernate-core/src/main/java/org/hibernate/MultiIdentifierLoadAccess.java
+++ b/hibernate-core/src/main/java/org/hibernate/MultiIdentifierLoadAccess.java
@@ -12,34 +12,53 @@ import org.hibernate.graph.GraphSemantic;
import org.hibernate.graph.RootGraph;
/**
- * Loads multiple entities at once by identifiers, ultimately via one of the
- * {@link #multiLoad} methods, using the various options specified (if any)
+ * Loads multiple instances of a given entity type at once, by
+ * specifying a list of identifier values. This allows the entities
+ * to be fetched from the database in batches.
+ *
+ * var graph = session.createEntityGraph(Book.class);
+ * graph.addSubgraph(Book_.publisher);
+ * session.byId(Book.class).withFetchGraph(graph).multiLoad(bookIds);
+ *
+ *
+ * @see Session#byMultipleIds(Class)
*
* @author Steve Ebersole
*/
public interface MultiIdentifierLoadAccess {
/**
- * Specify the {@link LockOptions} to use when retrieving the entity.
+ * Specify the {@linkplain LockOptions lock options} to use when
+ * querying the database.
*
- * @param lockOptions The lock options to use.
+ * @param lockOptions The lock options to use
*
* @return {@code this}, for method chaining
*/
MultiIdentifierLoadAccess with(LockOptions lockOptions);
/**
- * Specify the {@link CacheMode} to use when retrieving the entity.
+ * Specify the {@link CacheMode} to use when obtaining an entity.
*
- * @param cacheMode The CacheMode to use.
+ * @param cacheMode The {@code CacheMode} to use
*
* @return {@code this}, for method chaining
*/
MultiIdentifierLoadAccess with(CacheMode cacheMode);
+ /**
+ * Override the associations fetched by default by specifying
+ * the complete list of associations to be fetched as an
+ * {@linkplain jakarta.persistence.EntityGraph entity graph}.
+ */
default MultiIdentifierLoadAccess withFetchGraph(RootGraph graph) {
return with( graph, GraphSemantic.FETCH );
}
+ /**
+ * Augment the associations fetched by default by specifying a
+ * list of additional associations to be fetched as an
+ * {@linkplain jakarta.persistence.EntityGraph entity graph}.
+ */
default MultiIdentifierLoadAccess withLoadGraph(RootGraph graph) {
return with( graph, GraphSemantic.LOAD );
}
@@ -52,16 +71,28 @@ public interface MultiIdentifierLoadAccess {
return with( graph, GraphSemantic.LOAD );
}
+ /**
+ * Customize the associations fetched by specifying an
+ * {@linkplain jakarta.persistence.EntityGraph entity graph},
+ * and how it should be {@linkplain GraphSemantic interpreted}.
+ */
MultiIdentifierLoadAccess with(RootGraph graph, GraphSemantic semantic);
/**
- * Specify a batch size for loading the entities (how many at a time). The default is
- * to use a batch sizing strategy defined by the Dialect in use. Any greater-than-one
- * value here will override that default behavior. If giving an explicit value here,
- * care should be taken to not exceed the capabilities of the underlying database.
+ * Specify a batch size, that is, how many entities should be
+ * fetched in each request to the database.
+ *
+ * - By default, the batch sizing strategy is determined by the
+ * {@linkplain org.hibernate.dialect.Dialect#getBatchLoadSizingStrategy
+ * SQL dialect}, but
+ *
- if some {@code batchSize>1} is specified as an
+ * argument to this method, then that batch size will be used.
+ *
*
- * Note that overall a batch-size is considered a hint. How the underlying loading
- * mechanism interprets that is completely up to that underlying loading mechanism.
+ * If an explicit batch size is set manually, care should be taken
+ * to not exceed the capabilities of the underlying database.
+ *
+ * A batch size is considered a hint.
*
* @param batchSize The batch size
*
@@ -70,53 +101,58 @@ public interface MultiIdentifierLoadAccess {
MultiIdentifierLoadAccess withBatchSize(int batchSize);
/**
- * Specify whether we should check the {@link Session} to see whether the first-level cache already contains any of the
- * entities to be loaded in a managed state for the purpose of not including those
- * ids to the batch-load SQL.
+ * Specifies whether the ids of managed entity instances already
+ * cached in the current persistence context should be excluded
+ * from the list of ids sent to the database.
+ *
+ * By default, all ids are included and sent to the database.
*
- * @param enabled {@code true} enables this checking; {@code false} (the default) disables it.
+ * @param enabled {@code true} if they should be excluded;
+ * {@code false} if they should be included.
*
* @return {@code this}, for method chaining
*/
MultiIdentifierLoadAccess enableSessionCheck(boolean enabled);
/**
- * Should the multi-load operation be allowed to return entities that are locally
- * deleted? A locally deleted entity is one which has been passed to this
- * Session's {@link Session#delete} / {@link Session#remove} method, but not
- * yet flushed. The default behavior is to handle them as null in the return
- * (see {@link #enableOrderedReturn}).
+ * Should {@link #multiLoad} return entity instances that have been
+ * {@link Session#remove(Object) marked for removal} in the current
+ * session, but not yet {@code delete}d in the database?
+ *
+ * By default, instances marked for removal are replaced by null in
+ * the returned list of entities when {@link #enableOrderedReturn}
+ * is used.
*
- * @param enabled {@code true} enables returning the deleted entities;
- * {@code false} (the default) disables it.
+ * @param enabled {@code true} if removed entities should be returned;
+ * {@code false} if they should be replaced by null values.
*
* @return {@code this}, for method chaining
*/
MultiIdentifierLoadAccess enableReturnOfDeletedEntities(boolean enabled);
/**
- * Should the return List be ordered and positional in relation to the
- * incoming ids? If enabled (the default), the return List is ordered and
- * positional relative to the incoming ids. In other words, a request to
- * {@code multiLoad([2,1,3])} will return {@code [Entity#2, Entity#1, Entity#3]}.
+ * Should the returned list of entity instances be ordered, with the
+ * position of an entity instance determined by the position of its
+ * identifier in the list if ids passed to {@link #multiLoad}?
*
- * An important distinction is made here in regards to the handling of
- * unknown entities depending on this "ordered return" setting. If enabled
- * a null is inserted into the List at the proper position(s). If disabled,
- * the nulls are not put into the return List. In other words, consumers of
- * the returned ordered List would need to be able to handle null elements.
+ * By default, the returned list is ordered and the positions of the
+ * entities correspond to the positions of their ids. In this case,
+ * the {@linkplain #enableReturnOfDeletedEntities handling of entities
+ * marked for removal} becomes important.
*
- * @param enabled {@code true} (the default) enables ordering;
- * {@code false} disables it.
+ * @param enabled {@code true} if entity instances should be ordered;
+ * {@code false} if they may be returned in any order.
*
* @return {@code this}, for method chaining
*/
MultiIdentifierLoadAccess enableOrderedReturn(boolean enabled);
/**
- * Perform a load of multiple entities by identifiers. See {@link #enableOrderedReturn}
- * and {@link #enableReturnOfDeletedEntities} for options which effect
- * the size and "shape" of the return list.
+ * Retrieve the entities with the given identifiers.
+ *
+ * Note that the options {@link #enableReturnOfDeletedEntities} and
+ * {@link #enableOrderedReturn} affect the size and shape of the
+ * returned list of entity instances.
*
* @param The identifier type
*
@@ -126,9 +162,11 @@ public interface MultiIdentifierLoadAccess {
List multiLoad(K... ids);
/**
- * Perform a load of multiple entities by identifiers. See {@link #enableOrderedReturn}
- * and {@link #enableReturnOfDeletedEntities} for options which effect
- * the size and "shape" of the return list.
+ * Retrieve the entities with the given identifiers.
+ *
+ * Note that the options {@link #enableReturnOfDeletedEntities} and
+ * {@link #enableOrderedReturn} affect the size and shape of the
+ * returned list of entity instances.
*
* @param ids The ids to load
* @param The identifier type
diff --git a/hibernate-core/src/main/java/org/hibernate/NaturalIdLoadAccess.java b/hibernate-core/src/main/java/org/hibernate/NaturalIdLoadAccess.java
index 37d798733c..5024ff7a80 100644
--- a/hibernate-core/src/main/java/org/hibernate/NaturalIdLoadAccess.java
+++ b/hibernate-core/src/main/java/org/hibernate/NaturalIdLoadAccess.java
@@ -6,24 +6,37 @@
*/
package org.hibernate;
+import jakarta.persistence.metamodel.SingularAttribute;
+
+import java.util.Map;
import java.util.Optional;
/**
- * Loads an entity by its natural identifier.
+ * Loads an entity by its natural identifier, which may be a
+ * composite value comprising more than one attribute of the
+ * entity. If the entity has exactly one attribute annotated
+ * {@link org.hibernate.annotations.NaturalId @NaturalId},
+ * then {@link SimpleNaturalIdLoadAccess} may be used instead.
*
- * This is a generic form of load-by-natural-id covering both a single attribute
- * and multiple attributes as the natural-id. For natural-ids defined by a single
- * attribute, {@link SimpleNaturalIdLoadAccess} offers simplified access.
+ *
+ * Book book =
+ * session.byNaturalId(Book.class)
+ * .using(Book_.isbn, isbn)
+ * .using(Book_.printing, printing)
+ * .load();
+ *
*
* @author Eric Dalquist
* @author Steve Ebersole
*
+ * @see Session#byNaturalId(Class)
* @see org.hibernate.annotations.NaturalId
- * @see Session#byNaturalId
+ * @see SimpleNaturalIdLoadAccess
*/
public interface NaturalIdLoadAccess {
/**
- * Specify the {@link LockOptions} to use when retrieving the entity.
+ * Specify the {@linkplain LockOptions lock options} to use when
+ * querying the database.
*
* @param lockOptions The lock options to use.
*
@@ -32,9 +45,23 @@ public interface NaturalIdLoadAccess {
NaturalIdLoadAccess with(LockOptions lockOptions);
/**
- * Add a NaturalId attribute value.
+ * Add a {@link org.hibernate.annotations.NaturalId @NaturalId}
+ * attribute value in a typesafe way.
+ *
+ * @param attribute A typesafe reference to an attribute of the
+ * entity that is annotated {@code @NaturalId}
+ * @param value The value of the attribute
+ *
+ * @return {@code this}, for method chaining
+ */
+ NaturalIdLoadAccess using(SingularAttribute super T, X> attribute, X value);
+
+ /**
+ * Add a {@link org.hibernate.annotations.NaturalId @NaturalId}
+ * attribute value.
*
- * @param attributeName The entity attribute name that is marked as a NaturalId
+ * @param attributeName The name of an attribute of the entity
+ * that is annotated {@code @NaturalId}
* @param value The value of the attribute
*
* @return {@code this}, for method chaining
@@ -42,24 +69,54 @@ public interface NaturalIdLoadAccess {
NaturalIdLoadAccess using(String attributeName, Object value);
/**
- * Set multiple natural-id attribute values at once. The passed array is
- * expected to have an even number of elements, with the attribute name followed
- * by its value, for example, {@code using( "system", "matrix", "username", "neo" )}.
+ * Set multiple {@link org.hibernate.annotations.NaturalId @NaturalId}
+ * attribute values at once. An even number of arguments is expected,
+ * with each attribute name followed by its value, for example:
+ *
+ * Book book =
+ * session.byNaturalId(Book.class)
+ * .using(Map.of(Book_.ISBN, isbn, Book_.PRINTING, printing))
+ * .load();
+ *
*
* @return {@code this}, for method chaining
*/
+ NaturalIdLoadAccess using(Map mappings);
+
+ /**
+ * Set multiple {@link org.hibernate.annotations.NaturalId @NaturalId}
+ * attribute values at once. An even number of arguments is expected,
+ * with each attribute name followed by its value, for example:
+ *
+ * Book book =
+ * session.byNaturalId(Book.class)
+ * .using(Book_.ISBN, isbn, Book_.PRINTING, printing)
+ * .load();
+ *
+ *
+ * @return {@code this}, for method chaining
+ *
+ * @deprecated use {@link #using(Map)} with {@link Map#of}, which is
+ * slightly more typesafe
+ */
+ @Deprecated(since = "6.3")
NaturalIdLoadAccess using(Object... mappings);
/**
- * For entities with mutable natural ids, should natural ids be synchronized prior to performing a lookup?
- * The default, for correctness, is to synchronize.
+ * For entities with mutable natural ids, should natural ids be
+ * synchronized prior to executing a query? The default, for
+ * correctness, is to synchronize.
*
- * Here "synchronization" means updating the natural id to primary key cross-reference maintained by the
- * session. When enabled, prior to performing the lookup, Hibernate will check all entities of the given
- * type associated with the session to see if any natural id values have changed and, if so, update the
- * cross-reference. There is a performance penalty associated with this, so if it is completely certain
- * the no natural id in play has changed, this setting can be disabled to circumvent that impact.
- * Disabling this setting when natural id values have changed can result in incorrect results!
+ * Here "synchronization" means updating the natural id to
+ * primary key cross-reference maintained by the session. When
+ * enabled, prior to performing the lookup, Hibernate will check
+ * all entities of the given type associated with the session to
+ * see if any natural id values have changed and, if so, update
+ * the cross-reference. There is a performance penalty associated
+ * with this, so if it is completely certain the no natural id in
+ * play has changed, this setting can be disabled to circumvent
+ * that impact. Disabling this setting when natural id values
+ * have changed can lead to incorrect results!
*
* @param enabled Should synchronization be performed?
* {@code true} indicates synchronization will be performed;
@@ -70,31 +127,36 @@ public interface NaturalIdLoadAccess {
NaturalIdLoadAccess setSynchronizationEnabled(boolean enabled);
/**
- * Return the persistent instance with the natural id value(s) defined by the call(s) to {@link #using}. This
- * method might return a proxied instance that is initialized on-demand, when a non-identifier method is accessed.
+ * Return the persistent instance with the full natural id specified
+ * by previous calls to {@link #using}. This method might return a
+ * proxied instance that is initialized on-demand, when a non-identifier
+ * method is accessed.
*
- * You should not use this method to determine if an instance exists; to check for existence, use {@link #load}
- * instead. Use this only to retrieve an instance that you assume exists, where non-existence would be an
- * actual error.
+ * You should not use this method to determine if an instance exists;
+ * to check for existence, use {@link #load} instead. Use this method
+ * only to retrieve an instance that you assume exists, where
+ * non-existence would be an actual error.
*
* @return the persistent instance or proxy
*/
T getReference();
/**
- * Return the persistent instance with the natural id value(s) defined by the call(s) to {@link #using}, or
- * {@code null} if there is no such persistent instance. If the instance is already associated with the session,
- * return that instance, initializing it if needed. This method never returns an uninitialized instance.
+ * Return the persistent instance with the full natural id specified
+ * by previous calls to {@link #using}, or {@code null} if there is no
+ * such persistent instance. If the instance is already associated with
+ * the session, return that instance, initializing it if needed. This
+ * method never returns an uninitialized instance.
*
* @return The persistent instance or {@code null}
*/
T load();
/**
- * Same semantic as {@link #load} except that here {@link Optional} is returned to
- * handle nullability.
+ * Just like {@link #load}, except that here an {@link Optional} is
+ * returned.
*
- * @return The persistent instance, if one, wrapped in Optional
+ * @return The persistent instance, if one, as an {@link Optional}
*/
Optional loadOptional();
diff --git a/hibernate-core/src/main/java/org/hibernate/NaturalIdMultiLoadAccess.java b/hibernate-core/src/main/java/org/hibernate/NaturalIdMultiLoadAccess.java
index 426d0490b1..f05392b9bb 100644
--- a/hibernate-core/src/main/java/org/hibernate/NaturalIdMultiLoadAccess.java
+++ b/hibernate-core/src/main/java/org/hibernate/NaturalIdMultiLoadAccess.java
@@ -11,34 +11,60 @@ import java.util.Map;
import org.hibernate.graph.GraphSemantic;
import org.hibernate.graph.RootGraph;
-import org.hibernate.internal.util.collections.CollectionHelper;
+
+import static org.hibernate.internal.util.collections.CollectionHelper.asMap;
/**
- * Defines the ability to load multiple entities by simple natural-id simultaneously.
+ * Loads multiple instances of a given entity type at once, by
+ * specifying a list of natural id values. This allows the entities
+ * to be fetched from the database in batches.
+ *
+ * Composite natural ids may be accommodated by passing a list of
+ * maps of type {@code Map} to {@link #multiLoad}.
+ * Each map must contain the natural id attribute values keyed by
+ * {@link org.hibernate.annotations.NaturalId @NaturalId} attribute
+ * name.
+ *
+ * var compositeNaturalId =
+ * Map.of(Book_.ISBN, isbn, Book_.PRINTING, printing);
+ *
+ *
+ * @see Session#byMultipleNaturalId(Class)
*/
public interface NaturalIdMultiLoadAccess {
/**
- * Specify the {@link LockOptions} to use when retrieving the entity.
+ * Specify the {@linkplain LockOptions lock options} to use when
+ * querying the database.
*
- * @param lockOptions The lock options to use.
+ * @param lockOptions The lock options to use
*
* @return {@code this}, for method chaining
*/
NaturalIdMultiLoadAccess with(LockOptions lockOptions);
/**
- * Specify the {@link CacheMode} to use when retrieving the entity.
+ * Specify the {@link CacheMode} to use when obtaining an entity.
*
- * @param cacheMode The CacheMode to use.
+ * @param cacheMode The {@code CacheMode} to use
*
* @return {@code this}, for method chaining
*/
NaturalIdMultiLoadAccess with(CacheMode cacheMode);
+ /**
+ * Override the associations fetched by default by specifying
+ * the complete list of associations to be fetched as an
+ * {@linkplain jakarta.persistence.EntityGraph entity graph}.
+ */
default NaturalIdMultiLoadAccess withFetchGraph(RootGraph graph) {
return with( graph, GraphSemantic.FETCH );
}
+ /**
+ * Augment the associations fetched by default by specifying a
+ * list of additional associations to be fetched as an
+ * {@linkplain jakarta.persistence.EntityGraph entity graph}.
+ */
default NaturalIdMultiLoadAccess withLoadGraph(RootGraph graph) {
return with( graph, GraphSemantic.LOAD );
}
@@ -52,17 +78,27 @@ public interface NaturalIdMultiLoadAccess {
}
/**
- * Define a load or fetch graph to be used when retrieving the entity
+ * Customize the associations fetched by specifying an
+ * {@linkplain jakarta.persistence.EntityGraph entity graph},
+ * and how it should be {@linkplain GraphSemantic interpreted}.
*/
NaturalIdMultiLoadAccess with(RootGraph graph, GraphSemantic semantic);
/**
- * Specify a batch size for loading the entities (how many at a time). The default is
- * to use a batch sizing strategy defined by the Dialect in use. Any greater-than-one
- * value here will override that default behavior. If giving an explicit value here,
- * care should be taken to not exceed the capabilities of the underlying database.
+ * Specify a batch size, that is, how many entities should be
+ * fetched in each request to the database.
+ *
+ * - By default, the batch sizing strategy is determined by the
+ * {@linkplain org.hibernate.dialect.Dialect#getBatchLoadSizingStrategy
+ * SQL dialect}, but
+ *
- if some {@code batchSize>1} is specified as an
+ * argument to this method, then that batch size will be used.
+ *
*
- * Note that overall a batch-size is considered a hint.
+ * If an explicit batch size is set manually, care should be taken
+ * to not exceed the capabilities of the underlying database.
+ *
+ * A batch size is considered a hint.
*
* @param batchSize The batch size
*
@@ -71,68 +107,75 @@ public interface NaturalIdMultiLoadAccess {
NaturalIdMultiLoadAccess withBatchSize(int batchSize);
/**
- * Should the multi-load operation be allowed to return entities that are locally
- * deleted? A locally deleted entity is one which has been passed to this
- * Session's {@link Session#delete} / {@link Session#remove} method, but not
- * yet flushed. The default behavior is to handle them as null in the return
- * (see {@link #enableOrderedReturn}).
+ * Should {@link #multiLoad} return entity instances that have been
+ * {@link Session#remove(Object) marked for removal} in the current
+ * session, but not yet {@code delete}d in the database?
+ *
+ * By default, instances marked for removal are replaced by null in
+ * the returned list of entities when {@link #enableOrderedReturn}
+ * is used.
*
- * @param enabled {@code true} enables returning the deleted entities;
- * {@code false} (the default) disables it.
+ * @param enabled {@code true} if removed entities should be returned;
+ * {@code false} if they should be replaced by null values.
*
* @return {@code this}, for method chaining
*/
NaturalIdMultiLoadAccess enableReturnOfDeletedEntities(boolean enabled);
/**
- * Should the return List be ordered and positional in relation to the
- * incoming ids? If enabled (the default), the return List is ordered and
- * positional relative to the incoming ids. In other words, a request to
- * {@code multiLoad([2,1,3])} will return {@code [Entity#2, Entity#1, Entity#3]}.
+ * Should the returned list of entity instances be ordered, with the
+ * position of an entity instance determined by the position of its
+ * identifier in the list if ids passed to {@link #multiLoad}?
*
- * An important distinction is made here in regards to the handling of
- * unknown entities depending on this "ordered return" setting. If enabled
- * a null is inserted into the List at the proper position(s). If disabled,
- * the nulls are not put into the return List. In other words, consumers of
- * the returned ordered List would need to be able to handle null elements.
+ * By default, the returned list is ordered and the positions of the
+ * entities correspond to the positions of their ids. In this case,
+ * the {@linkplain #enableReturnOfDeletedEntities handling of entities
+ * marked for removal} becomes important.
*
- * @param enabled {@code true} (the default) enables ordering;
- * {@code false} disables it.
+ * @param enabled {@code true} if entity instances should be ordered;
+ * {@code false} if they may be returned in any order.
*
* @return {@code this}, for method chaining
*/
NaturalIdMultiLoadAccess enableOrderedReturn(boolean enabled);
/**
- * Perform a load of multiple entities by natural-id.
+ * Retrieve the entities with the given natural id values.
*
- * See {@link #enableOrderedReturn} and {@link #enableReturnOfDeletedEntities}
- * for options which effect the size and "shape" of the return list.
+ * Note that the options {@link #enableReturnOfDeletedEntities} and
+ * {@link #enableOrderedReturn} affect the size and shape of the
+ * returned list of entity instances.
*
- * @param ids The natural-id values to load
+ * @param ids The natural id values to load
*
* @return The managed entities.
*/
List multiLoad(Object... ids);
/**
- * Perform a load of multiple entities by natural-id.
+ * Retrieve the entities with the given natural id values.
*
- * See {@link #enableOrderedReturn} and {@link #enableReturnOfDeletedEntities}
- * for options which effect the size and "shape" of the return list.
+ * Note that the options {@link #enableReturnOfDeletedEntities} and
+ * {@link #enableOrderedReturn} affect the size and shape of the
+ * returned list of entity instances.
*
- * @param ids The natural-id values to load
+ * @param ids The natural id values to load
*
* @return The managed entities.
*/
List multiLoad(List> ids);
/**
- * Helper for creating a Map that represents the value of a compound natural-id
- * for use in loading. The passed array is expected to have an even number of elements
- * representing key, value pairs. E.g. `using( "system", "matrix", "username", "neo" )`
+ * Helper for creating a {@link Map} that represents the value of a
+ * composite natural id. An even number of arguments is expected,
+ * with each attribute name followed by its value.
+ *
+ * @see NaturalIdLoadAccess#using(Object...)
+ *
+ * @deprecated use {@link Map#of} instead
*/
+ @Deprecated(since = "6.3")
static Map compoundValue(Object... elements) {
- return CollectionHelper.asMap( elements );
+ return asMap( elements );
}
}
diff --git a/hibernate-core/src/main/java/org/hibernate/SimpleNaturalIdLoadAccess.java b/hibernate-core/src/main/java/org/hibernate/SimpleNaturalIdLoadAccess.java
index 9aaa55f414..44c4b71e47 100644
--- a/hibernate-core/src/main/java/org/hibernate/SimpleNaturalIdLoadAccess.java
+++ b/hibernate-core/src/main/java/org/hibernate/SimpleNaturalIdLoadAccess.java
@@ -9,69 +9,88 @@ package org.hibernate;
import java.util.Optional;
/**
- * Loads an entity by its natural identifier.
+ * Loads an entity by its natural identifier. This simplified API is
+ * used when the entity has exactly one field or property annotated
+ * {@link org.hibernate.annotations.NaturalId @NaturalId}. If an
+ * entity has multiple attributes annotated {@code @NaturalId}, then
+ * {@link NaturalIdLoadAccess} should be used instead.
+ *
+ *
+ * Book book = session.bySimpleNaturalId(Book.class).load(isbn);
+ *
*
* @author Eric Dalquist
* @author Steve Ebersole
*
+ * @see Session#bySimpleNaturalId(Class)
* @see org.hibernate.annotations.NaturalId
* @see NaturalIdLoadAccess
*/
public interface SimpleNaturalIdLoadAccess {
/**
- * Specify the {@link LockOptions} to use when retrieving the entity.
+ * Specify the {@linkplain LockOptions lock options} to use when
+ * querying the database.
*
- * @param lockOptions The lock options to use.
+ * @param lockOptions The lock options to use
*
* @return {@code this}, for method chaining
*/
SimpleNaturalIdLoadAccess with(LockOptions lockOptions);
/**
- * For entities with mutable natural ids, should Hibernate perform "synchronization" prior to performing
- * lookups? The default is to perform "synchronization" (for correctness).
+ * For entities with mutable natural ids, should Hibernate perform
+ * "synchronization" prior to performing lookups? The default is
+ * to perform "synchronization" (for correctness).
*
- * See {@link NaturalIdLoadAccess#setSynchronizationEnabled} for detailed discussion.
+ * See {@link NaturalIdLoadAccess#setSynchronizationEnabled} for
+ * detailed discussion.
*
- * @param enabled Should synchronization be performed? {@code true} indicates synchronization will be performed;
- * {@code false} indicates it will be circumvented.
+ * @param enabled Should synchronization be performed?
+ * {@code true} indicates synchronization will be performed;
+ * {@code false} indicates it will be circumvented.
*
* @return {@code this}, for method chaining
*/
SimpleNaturalIdLoadAccess setSynchronizationEnabled(boolean enabled);
/**
- * Return the persistent instance with the given natural id value, assuming that the instance exists. This method
- * might return a proxied instance that is initialized on-demand, when a non-identifier method is accessed.
+ * Return the persistent instance with the given natural id value,
+ * assuming that the instance exists. This method might return a
+ * proxied instance that is initialized on-demand, when a
+ * non-identifier method is accessed.
+ *
+ * You should not use this method to determine if an instance exists;
+ * to check for existence, use {@link #load} instead. Use this only to
+ * retrieve an instance that you assume exists, where non-existence
+ * would be an actual error.
*
- * You should not use this method to determine if an instance exists; to check for existence, use {@link #load}
- * instead. Use this only to retrieve an instance that you assume exists, where non-existence would be an
- * actual error.
+ * @param naturalIdValue The value of the natural id
*
- * @param naturalIdValue The value of the natural-id for the entity to retrieve
- *
- * @return The persistent instance or proxy, if an instance exists. Otherwise, {@code null}.
+ * @return The persistent instance or proxy, if an instance exists.
+ * Otherwise, {@code null}.
*/
T getReference(Object naturalIdValue);
/**
- * Return the persistent instance with the given natural id value, or {@code null} if there is no such persistent
- * instance. If the instance is already associated with the session, return that instance, initializing it if
- * needed. This method never returns an uninitialized instance.
+ * Return the persistent instance with the given natural id value,
+ * or {@code null} if there is no such persistent instance. If the
+ * instance is already associated with the session, return that
+ * instance, initializing it if needed. This method never returns
+ * an uninitialized instance.
*
- * @param naturalIdValue The value of the natural-id for the entity to retrieve
+ * @param naturalIdValue The value of the natural-id
*
* @return The persistent instance or {@code null}
*/
T load(Object naturalIdValue);
/**
- * Same semantic as {@link #load} except that here {@link Optional} is returned to
- * handle nullability.
+ * Just like {@link #load}, except that here an {@link Optional}
+ * is returned.
*
* @param naturalIdValue The identifier
*
- * @return The persistent instance, if one, wrapped in Optional
+ * @return The persistent instance, if any, as an {@link Optional}
*/
Optional loadOptional(Object naturalIdValue);
}
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 d1faf3829e..32eec4acd7 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
@@ -10,9 +10,9 @@ import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;
+import jakarta.persistence.metamodel.SingularAttribute;
import org.hibernate.LockOptions;
import org.hibernate.NaturalIdLoadAccess;
-import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.mapping.EntityMappingType;
@@ -31,6 +31,12 @@ public class NaturalIdLoadAccessImpl extends BaseNaturalIdLoadAccessImpl i
return (NaturalIdLoadAccessImpl) super.with( lockOptions );
}
+ @Override
+ public NaturalIdLoadAccess using(SingularAttribute super T, X> attribute, X value) {
+ naturalIdParameters.put( attribute.getName(), value );
+ return this;
+ }
+
@Override
public NaturalIdLoadAccess using(String attributeName, Object value) {
naturalIdParameters.put( attributeName, value );
@@ -38,6 +44,12 @@ public class NaturalIdLoadAccessImpl extends BaseNaturalIdLoadAccessImpl i
}
@Override
+ public NaturalIdLoadAccess using(Map mappings) {
+ naturalIdParameters.putAll( mappings );
+ return this;
+ }
+
+ @Override @Deprecated
public NaturalIdLoadAccess using(Object... mappings) {
CollectionHelper.collectMapEntries( naturalIdParameters::put, mappings );
return this;
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/identifier/MultipleNaturalIdTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/identifier/MultipleNaturalIdTest.java
index 03d1471294..d2aa07dd52 100644
--- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/identifier/MultipleNaturalIdTest.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/identifier/MultipleNaturalIdTest.java
@@ -7,9 +7,8 @@
package org.hibernate.orm.test.mapping.identifier;
import java.io.Serializable;
+import java.util.Map;
import java.util.Objects;
-import jakarta.persistence.Embeddable;
-import jakarta.persistence.Embedded;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
@@ -67,6 +66,16 @@ public class MultipleNaturalIdTest extends BaseEntityManagerFunctionalTestCase {
.load();
//end::naturalid-load-access-example[]
+ assertEquals("High-Performance Java Persistence", book.getTitle());
+ });
+ doInJPA(this::entityManagerFactory, entityManager -> {
+ Publisher publisher = entityManager.getReference(Publisher.class, 1L);
+ Book book = entityManager
+ .unwrap(Session.class)
+ .byNaturalId(Book.class)
+ .using(Map.of("productNumber", "973022823X", "publisher", publisher))
+ .load();
+
assertEquals("High-Performance Java Persistence", book.getTitle());
});
}
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/naturalid/CompoundNaturalIdTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/naturalid/CompoundNaturalIdTests.java
index 18075ed749..1c403c4391 100644
--- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/naturalid/CompoundNaturalIdTests.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/naturalid/CompoundNaturalIdTests.java
@@ -190,8 +190,8 @@ public class CompoundNaturalIdTests {
final NaturalIdMultiLoadAccess loadAccess = session.byMultipleNaturalId( Account.class );
loadAccess.enableOrderedReturn( false );
final List accounts = loadAccess.multiLoad(
- NaturalIdMultiLoadAccess.compoundValue( "system", "matrix", "username", "neo" ),
- NaturalIdMultiLoadAccess.compoundValue( "system", "matrix", "username", "trinity" )
+ Map.of( "system", "matrix", "username", "neo" ),
+ Map.of( "system", "matrix", "username", "trinity" )
);
assertThat( accounts.size(), is( 2 ) );