diff --git a/documentation/src/main/asciidoc/introduction/Interacting.adoc b/documentation/src/main/asciidoc/introduction/Interacting.adoc index 238a2a020e..e546c8fe29 100644 --- a/documentation/src/main/asciidoc/introduction/Interacting.adoc +++ b/documentation/src/main/asciidoc/introduction/Interacting.adoc @@ -337,6 +337,72 @@ We're getting a bit ahead of ourselves here, but let's quickly mention the gener Instead, fetch all the data you'll need upfront at the beginning of a unit of work, using one of the techniques described in <>, usually, using _join fetch_ in HQL. ==== +It's clear we need a way to request that an association be _eagerly_ fetched using a database `join`. +One way to do that is by passing an `EntityGraph` to `find()`. + +[[entity-graph]] +=== Entity graphs and eager fetching + +When an association is mapped `fetch=LAZY`, it won't, by default, be fetched when we call the `find()` method. +We may request that an association be fetched eagerly (immediately) by passing an `EntityGraph` to `find()`. + +The JPA-standard API for this is a bit unwieldy: + +[source,java] +---- +var graph = entityManager.createEntityGraph(Book.class); +graph.addSubgraph(Book_.publisher); +entityManager.find(Book.class, bookId, Map.of(SpecHints.HINT_SPEC_FETCH_GRAPH, graph)); +---- + +This is untypesafe and a bit verbose. +Hibernate has a better way: + +[source,java] +---- +var graph = session.createEntityGraph(Book.class); +graph.addSubgraph(Book_.publisher); +session.byId(Book.class).fetching(graph).load(bookId); +---- + +This code adds a `left outer join` to our SQL query, fetching the associated `Publisher` along with the `Book`. + +We may even attach additional nodes to our `EntityGraph`: + +[source,java] +---- +var graph = session.createEntityGraph(Book.class); +graph.addSubgraph(Book_.publisher); +graph.addPluralSubgraph(Book_.authors).addSubgraph(Author_.person); +session.byId(Book.class).fetching(graph).load(bookId); + +---- + +This results in a SQL query with _four_ ``left outer join``s. + +[NOTE] +==== +In the code examples above, we're making use of the JPA static metamodel. +The classes `Book_` and `Author_` are generated by the annotation processor we have in our <>, one of the <> of Hibernate. +They let us refer to attributes of our model in a completely type-safe way. +We'll use them again, below, when we talk about <>. +==== + +JPA specifies that any given `EntityGraph` may be interpreted in two different ways. + +- A _fetch graph_ specifies exactly the associations that should be eagerly loaded. + Any association not belonging to the entity graph is proxied and loaded lazily only if required. +- A _load graph_ specifies that the associations in the entity graph are to be fetched in addition to the associations mapped `fetch=EAGER`. + +You're right, the names make no sense. +But don't worry, if you take our advice, and map your associations `fetch=LAZY`, there's no difference between a "fetch" graph and a "load" graph, so the names don't matter. + +[NOTE] +==== +JPA even specifies a way to define named entity graphs using annotations. +But the annotation-based API is so verbose that it's just not worth using. +==== + [[flush]] === Flushing the session diff --git a/documentation/src/main/asciidoc/introduction/Mapping.adoc b/documentation/src/main/asciidoc/introduction/Mapping.adoc index e70db4f842..e9d9d1a9d1 100644 --- a/documentation/src/main/asciidoc/introduction/Mapping.adoc +++ b/documentation/src/main/asciidoc/introduction/Mapping.adoc @@ -559,7 +559,7 @@ So we don't usually need to explicitly specify that a column should be of type ` The constant values defined in the class `org.hibernate.Length` are very helpful here: .Predefined column lengths -[%autowidth.stretch] +[cols="10,12,~"] |=== | Constant | Value | Description