Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitf50c43e

Browse files
committed
HHH-19878 explain how to use find() to control merge()
1 parentfc0d11b commitf50c43e

File tree

1 file changed

+40
-6
lines changed

1 file changed

+40
-6
lines changed

‎documentation/src/main/asciidoc/introduction/Interacting.adoc‎

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -643,23 +643,57 @@ Notice that this code fragment is completely typesafe, again thanks to <<metamod
643643
[[controlling-merge]]
644644
=== Controlling state retrieval during merge
645645

646-
When <<persistence-operations,`merge()`>> is used with cascading, that is, when the `merge()` operation is applied to a root entity with associations mapped `cascade=MERGE`, Hibernate issues a single `select` statement to retrieve the current database state associated with the entity and its associated entities.
647-
In certain circumstances, this query might be suboptimal.
648-
However, this query does not occur if the root entity was already loaded into the persistence context before `merge()` is called.
646+
The <<persistence-operations,`merge()`>> operation is usually used when some interaction with a user or automated system spans multiple transactions, with each transaction having its own persistence context:
649647

650-
Therefore, we may gain control over the way state is loaded before a `merge()` just by calling `find()` before calling `merge()`.
648+
1. an entity `e` is retrieved in one persistence context, and then the current transaction ends, resulting in destruction of the persistence context and in the entity becoming detached, then
649+
2. `e` is modified in some way while detached, and then
650+
3. finally, the modification is made persistent by merging the detached instance in a second transaction, with a new persistence context, by calling `session.merge(e)`.
651+
652+
In step 3, the original entity instance `e` remains detached, but `merge()` returns a distinct instance `f` representing the same row of the database and associated with the new persistence context.
653+
That is, `merge()` trades a detached instance for a <<persistence-contexts,persistent instance>> representing the same row.
654+
655+
To determine the nature of the modification held in `e` and to guarantee correct semantics with respect to optimistic locking, Hibernate first ``select``s the current persistent state of the entity from the database before applying the modification to `f`.
656+
657+
<<cascade,Cascade merge>> allows multiple modifications held in a graph of entity instances to be made persistent in one call to `merge()`.
658+
When `merge()` is used with cascading -- that is, when the `merge()` operation is applied to a root entity with associations mapped `cascade=MERGE` -- Hibernate issues a single `select` statement to retrieve the current database state of the root entity and all its associated entities.
659+
This behavior avoids the use of N+1 select statements for state retrieval during cascade merge but, in certain circumstances, the query might be suboptimal.
660+
On the other hand, this query does not occur if the root entity was already loaded into the persistence context before `merge()` is called.
661+
662+
Therefore, when using the `EntityManager` API, we may gain control over the way state is loaded before a `merge()` just by calling `find()` before calling `merge()`.
651663

652664
[source,java]
653665
----
654666
Book book = ... ;
655-
var graph =session.createEntityGraph(Book.class);
667+
var graph =entityManager.createEntityGraph(Book.class);
656668
graph.addSubgraph(Book_.chapters); // Book.chapters mapped cascade=MERGE
657669
entityManager.find(graph, book.getIsbn()); // force loading of the book
658-
entityManager.merge(book);
670+
entityManager.merge(book); // merge the detached objet
671+
----
672+
673+
The `Session` interface provides a streamlined alternative:
674+
675+
[source,java]
676+
----
677+
Book book = ... ;
678+
var graph = session.createEntityGraph(Book.class);
679+
graph.addSubgraph(Book_.chapters);
680+
session.merge(book, graph); // equivalent to find() then merge()
659681
----
660682

661683
When merging multiple root entities, `findMultiple()` may be used instead of `find()`.
662684

685+
[source,java]
686+
----
687+
List<Book> books = ... ;
688+
var isbns = books.stream().map(Book::getIsbn).toList();
689+
var graph = session.createEntityGraph(Book.class);
690+
graph.addSubgraph(Book_.chapters); // Book.chapters mapped cascade=MERGE
691+
session.findMultiple(graph, isbns); // force loading of the books
692+
for (var book in books) {
693+
session.merge(book);
694+
}
695+
----
696+
663697
TIP: In some cases, `merge()` is much less efficient than the `upsert()` operation of <<stateless-sessions,`StatelessSession`>>.
664698

665699
[[flush]]

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp