Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
Original file line number Diff line number Diff line change
Expand Up @@ -135,50 +135,50 @@ Unless the entity class is declared `final`, the proxy extends the entity class.
=== Obtain an entity with its data initialized

It is also quite common to want to obtain an entity along with its data (e.g. like when we need to display it in the UI).
Hibernate offers two flavors of this operation:

[[pc-find-jpa-example]]
.Obtaining an entity reference with its data initialized with Jakarta Persistence
find():: Performs the requested lookup, returning `null` if no matching row was found.
get():: Performs the requested lookup, throwing an exception if no matching row was found.

[[pc-find-example]]
.Finding an initialized entity reference
====
[source, java, indent=0]
----
include::{example-dir-pc}/PersistenceContextTest.java[tags=pc-find-jpa-example]
include::{example-dir-pc}/PersistenceContextTest.java[tags=pc-find-example]
----
====

[[pc-find-native-example]]
.Obtaining an entity reference with its data initialized with Hibernate API
[[pc-get-example]]
.Getting an initialized entity reference
====

[source, java, indent=0]
----
include::{example-dir-pc}/PersistenceContextTest.java[tags=pc-find-native-example]
include::{example-dir-pc}/PersistenceContextTest.java[tags=pc-get-example]
----
====

[[pc-find-by-id-native-example]]
.Obtaining an entity reference with its data initialized using the `byId()` Hibernate API
====
Hibernate also offers a consistent way to `find()` and `get()` an entity by its <<naturalid>>.

[[pc-find-by-natual-id-example]]
.Finding an entity by natural-id
====
[source, java, indent=0]
----
include::{example-dir-pc}/PersistenceContextTest.java[tags=pc-find-by-id-native-example]
include::{example-dir-pc}/PersistenceContextTest.java[tags=pc-find-by-natural-id-example]
----
====

In both cases null is returned if no matching database row was found.

It's possible to return a Java 8 `Optional` as well:

[[tag::pc-find-optional-by-id-native-example]]
.Obtaining an Optional entity reference with its data initialized using the `byId()` Hibernate API
[[pc-get-by-natual-id-example]]
.Getting an entity by natural-id
====

[source, java, indent=0]
----
include::{example-dir-pc}/PersistenceContextTest.java[tags=pc-find-optional-by-id-native-example]
include::{example-dir-pc}/PersistenceContextTest.java[tags=pc-get-by-natural-id-example]
----
====


[[pc-by-multiple-ids]]
=== Obtain multiple entities by their identifiers

Expand All @@ -202,8 +202,8 @@ Hibernate offers this functionality via the `Session#findMultiple` methods which
Now, assuming we have 3 `Person` entities in the database, we can load all of them with a single call
as illustrated by the following example:

[[tag::pc-by-multiple-ids-example]]
.Loading multiple entities using the `findMultiple()` Hibernate API
[[tag::pc-find-multiple-example]]
.Loading multiple entities using `findMultiple()`
====

[source, java, indent=0]
Expand All @@ -212,63 +212,30 @@ include::{example-dir-pc}/FindMultipleDocTests.java[tags=pc-find-multiple-exampl
----
====

[[pc-find-natural-id]]
=== Obtain an entity by natural-id
There is also `getMultiple()` which behaves in a similar manner to `get()` in that an exception is thrown if any of the identifiers could not be located.

In addition to allowing to load the entity by its identifier, Hibernate allows applications to load entities by the declared natural identifier.

[[pc-find-by-natural-id-entity-example]]
.Natural-id mapping
====
[source, java, indent=0]
----
include::{example-dir-pc}/PersistenceContextTest.java[tags=pc-find-by-natural-id-entity-example]
----
[[tag::pc-get-multiple-example]]
.Loading multiple entities using `getMultiple()`
====

We can also opt to fetch the entity or just retrieve a reference to it when using the natural identifier loading methods.

[[pc-find-by-simple-natural-id-example]]
.Get entity reference by simple natural-id
====
[source, java, indent=0]
----
include::{example-dir-pc}/PersistenceContextTest.java[tags=pc-find-by-simple-natural-id-example]
----
====

[[pc-find-by-natural-id-example]]
.Load entity by natural-id
====
[source, java, indent=0]
----
include::{example-dir-pc}/PersistenceContextTest.java[tags=pc-find-by-natural-id-example]
include::{example-dir-pc}/FindMultipleDocTests.java[tags=pc-find-multiple-example]
----
====

We can also use a Java 8 `Optional` to load an entity by its natural id:
Note that `findMultiple()` and `getMultiple()` both support loading by natural-id as well with the same semantics.

[[pc-find-optional-by-simple-natural-id-example]]
.Load an Optional entity by natural-id
[[tag::pc-get-multiple-example]]
.Loading multiple entities using `getMultiple()`
====

[source, java, indent=0]
----
include::{example-dir-pc}/PersistenceContextTest.java[tags=pc-find-optional-by-simple-natural-id-example]
include::{example-dir-pc}/FindMultipleDocTests.java[tags=pc-find-multiple-natural-id-example]
----
====

Hibernate offers a consistent API for accessing persistent data by identifier or by the natural-id. Each of these defines the same two data access methods:

getReference::
Should be used in cases where the identifier is assumed to exist, where non-existence would be an actual error.
Should never be used to test existence.
That is because this method will prefer to create and return a proxy if the data is not already associated with the Session rather than hit the database.
The quintessential use-case for using this method is to create foreign key based associations.
load::
Will return the persistent data associated with the given identifier value or null if that identifier does not exist.

Each of these two methods defines an overloading variant accepting a `org.hibernate.LockOptions` argument.
Locking is discussed in a separate <<chapters/locking/Locking.adoc#locking,chapter>>.

[[pc-filtering]]
=== Filtering entities and associations
Expand Down
4 changes: 2 additions & 2 deletions hibernate-core/hibernate-core.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -128,12 +128,12 @@ xjc {
xjcPlugins('inheritance', 'simplify')
}
configuration {
xsdFile = file( 'src/main/resources/org/hibernate/xsd/cfg/configuration-3.2.0.xsd' )
xsdFile = file( 'src/main/resources/org/hibernate/xsd/cfg/configuration-8.0.xsd' )
xjcBindingFile = file( 'src/main/xjb/configuration-bindings.xjb' )
xjcPlugins('inheritance', 'simplify')
}
mapping {
xsdFile = file( 'src/main/resources/org/hibernate/xsd/mapping/mapping-7.0.xsd' )
xsdFile = file( 'src/main/resources/org/hibernate/xsd/mapping/mapping-8.0.xsd' )
xjcBindingFile = file( 'src/main/xjb/mapping-bindings.xjb' )
xjcPlugins('inheritance', 'simplify')
}
Expand Down
22 changes: 19 additions & 3 deletions hibernate-core/src/main/java/org/hibernate/Locking.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,7 @@ enum Scope implements FindOption, LockOption, RefreshOption {
/**
* All tables with fetched rows will be locked.
*
* @apiNote This is Hibernate's legacy behavior, and has no
* corresponding JPA scope.
* @see PessimisticLockScope#FETCHED
*/
INCLUDE_FETCHES;

Expand All @@ -86,11 +85,14 @@ public PessimisticLockScope getCorrespondingJpaScope() {
return switch (this) {
case ROOT_ONLY -> PessimisticLockScope.NORMAL;
case INCLUDE_COLLECTIONS -> PessimisticLockScope.EXTENDED;
case INCLUDE_FETCHES -> null;
case INCLUDE_FETCHES -> PessimisticLockScope.FETCHED;
};
}

public static Scope fromJpaScope(PessimisticLockScope scope) {
if ( scope == PessimisticLockScope.FETCHED ) {
return INCLUDE_FETCHES;
}
if ( scope == PessimisticLockScope.EXTENDED ) {
return INCLUDE_COLLECTIONS;
}
Expand All @@ -104,6 +106,20 @@ public static Scope interpret(String name) {
}
return valueOf( name.toUpperCase( Locale.ROOT ) );
}

public static Scope fromHint(Object hintValue) {
assert hintValue != null;

if ( hintValue instanceof Scope scope ) {
return scope;
}

if ( hintValue instanceof PessimisticLockScope jpaScope ) {
return fromJpaScope( jpaScope );
}

return valueOf( hintValue.toString().toUpperCase( Locale.ROOT ) );
}
}

/**
Expand Down
77 changes: 6 additions & 71 deletions hibernate-core/src/main/java/org/hibernate/Session.java
Original file line number Diff line number Diff line change
Expand Up @@ -486,24 +486,6 @@ public interface Session extends SharedSessionContract, EntityManager {
@Override
<T> T find(Class<T> entityType, Object id, FindOption... options);

/// Return the persistent instance of the named entity type with the given identifier,
/// or null if there is no such persistent instance.
///
/// Differs from {@linkplain #find(Class, Object)} in that this form accepts
/// the entity name of a [dynamic entity][org.hibernate.metamodel.RepresentationMode#MAP].
///
/// @see #find(Class, Object)
Object find(String entityName, Object primaryKey);

/// Return the persistent instance of the named entity type with the given identifier
/// using the specified options, or null if there is no such persistent instance.
///
/// Differs from [#find(Class, Object, FindOption...)] in that this form accepts
/// the entity name of a [dynamic entity][org.hibernate.metamodel.RepresentationMode#MAP].
///
/// @see #find(Class, Object, FindOption...)
Object find(String entityName, Object primaryKey, FindOption... options);

/// Return the persistent instances of the given entity class with the given identifiers
/// as a list. 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
Expand Down Expand Up @@ -801,39 +783,6 @@ public interface Session extends SharedSessionContract, EntityManager {
@Override
void clear();

/// Return the persistent instance of the given entity class 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. This method never returns an uninitialized
/// instance.
///
/// The object returned by `get()` or `find()` is either an unproxied instance
/// of the given entity class, or a fully-fetched proxy object.
///
/// This operation requests [LockMode#NONE], that is, no lock, allowing the object
/// to be retrieved from the cache without the cost of database access. However, if it is
/// necessary to read the state from the database, the object will be returned with the
/// lock mode [LockMode#READ].
///
/// To bypass the second-level cache, and ensure that the state is read from the database,
/// either:
///
/// - call [#get(Class,Object,LockMode)] with the explicit lock mode
/// [LockMode#READ], or
/// - {@linkplain #setCacheMode set the cache mode} to [CacheMode#IGNORE]
/// before calling this method.
///
/// @apiNote This operation is very similar to [#find(Class,Object)].
///
/// @param entityType the entity type
/// @param id an identifier
///
/// @return a persistent instance or null
///
/// @deprecated Because the semantics of this method may change in a future release.
/// Use [#find(Class,Object)] instead.
@Deprecated(since = "7.0", forRemoval = true)
<T> T get(Class<T> entityType, Object id);

/// Return the persistent instance of the given entity class 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. This method never returns an uninitialized
Expand All @@ -851,26 +800,6 @@ public interface Session extends SharedSessionContract, EntityManager {
@Deprecated(since = "7.0", forRemoval = true)
<T> T get(Class<T> entityType, Object id, LockMode lockMode);

/// Return the persistent instance of the given named entity 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. This method never returns an uninitialized
/// instance.
///
/// @param entityName the entity name
/// @param id an identifier
///
/// @return a persistent instance or null
///
/// @deprecated The semantics of this method may change in a future release.
/// Use [SessionFactory#createGraphForDynamicEntity(String)]
/// together with [#find(EntityGraph,Object,FindOption...)]
/// to load [dynamic entities][org.hibernate.metamodel.RepresentationMode#MAP].
///
/// @see SessionFactory#createGraphForDynamicEntity(String)
/// @see #find(EntityGraph, Object, FindOption...)
@Deprecated(since = "7", forRemoval = true)
Object get(String entityName, Object id);

/// Return the persistent instance of the given entity class 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. This method never returns an uninitialized
Expand Down Expand Up @@ -1402,4 +1331,10 @@ public interface Session extends SharedSessionContract, EntityManager {
default <T> T unwrap(Class<T> type) {
return SharedSessionContract.super.unwrap(type);
}

/// @deprecated (since 8.0) Use #createNamedQuery instead. Still here to allow for
/// forms using Hibernate's legacy result-set building, though such usages should
/// move to using [jakarta.persistence.sql.ResultSetMapping].
@Deprecated @SuppressWarnings("rawtypes")
NativeQuery getNamedNativeQuery(String name);
}
Loading
Loading