HHH-11186 - Add examples for all Hibernate annotations
Document more annotations: - @LazyCollection
This commit is contained in:
parent
f8d366e749
commit
ab9016306b
|
@ -895,6 +895,8 @@ The `TRUE` and `FALSE` values are deprecated since you should be using the JPA h
|
|||
The `EXTRA` value has no equivalent in the JPA specification, and it's used to avoid loading the entire collection even when the collection is accessed for the first time.
|
||||
Each element is fetched individually using a secondary query.
|
||||
|
||||
See the <<chapters/fetching/Fetching.adoc#fetching-LazyCollection, `@LazyCollection` mapping>> section for more info.
|
||||
|
||||
[[annotations-hibernate-lazygroup]]
|
||||
==== `@LazyGroup`
|
||||
|
||||
|
|
|
@ -352,3 +352,72 @@ include::{extrasdir}/fetching-strategies-fetch-mode-join-example.sql[]
|
|||
====
|
||||
|
||||
This time, there was no secondary query because the child collection was loaded along with the parent entity.
|
||||
|
||||
[[fetching-LazyCollection]]
|
||||
=== `@LazyCollection`
|
||||
|
||||
The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/LazyCollection.html[`@LazyCollection`] annotation is used to specify the lazy fetching behavior of a given collection.
|
||||
The possible values are given by the `https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/LazyCollectionOption.html[LazyCollectionOption]` enumeration:
|
||||
|
||||
`TRUE`:: Load it when the state is requested.
|
||||
`FALSE`:: Eagerly load it.
|
||||
`EXTRA`:: Prefer extra queries over full collection loading.
|
||||
|
||||
The `TRUE` and `FALSE` values are deprecated since you should be using the JPA http://docs.oracle.com/javaee/7/api/javax/persistence/FetchType.html[`FetchType`] attribute of the <<annotations-jpa-elementcollection>>, <<annotations-jpa-onetomany>>, or <<annotations-jpa-manytomany>> collection.
|
||||
|
||||
The `EXTRA` value has no equivalent in the JPA specification, and it's used to avoid loading the entire collection even when the collection is accessed for the first time.
|
||||
Each element is fetched individually using a secondary query.
|
||||
|
||||
[[fetching-LazyCollection-domain-model-example]]
|
||||
.`LazyCollectionOption.EXTRA` mapping example
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/LazyCollectionTest.java[tags=fetching-LazyCollection-domain-model-example]
|
||||
----
|
||||
====
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
`LazyCollectionOption.EXTRA` only works for ordered collections,
|
||||
either List(s) that are annotated with @OrderColumn or Map(s).
|
||||
|
||||
For bags (e.g. regular List(s) of entities that do not preserve any certain ordering),
|
||||
the @LazyCollection(LazyCollectionOption.EXTRA)` behaves like any other `FetchType.LAZY` collection
|
||||
(the collection is fetched entirely upon being accessed for the first time).
|
||||
====
|
||||
|
||||
Now, considering we have the following entities:
|
||||
|
||||
[[fetching-LazyCollection-persist-example]]
|
||||
.`LazyCollectionOption.EXTRA` Domain Model example
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/LazyCollectionTest.java[tags=fetching-LazyCollection-persist-example]
|
||||
----
|
||||
====
|
||||
|
||||
When fetching the `employee` collection entries by their position in the `List`,
|
||||
Hibernate generates the following SQL statements:
|
||||
|
||||
[[fetching-LazyCollection-select-example]]
|
||||
.`LazyCollectionOption.EXTRA` fetching example
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/LazyCollectionTest.java[tags=fetching-LazyCollection-select-example]
|
||||
----
|
||||
|
||||
[source, SQL, indent=0]
|
||||
----
|
||||
include::{extrasdir}/fetching-LazyCollection-select-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
[WARNING]
|
||||
====
|
||||
Therefore, the child entities were fetched one after the other without triggering a full collection initialization.
|
||||
|
||||
For this reason, caution is advised because `LazyCollectionOption.EXTRA` lazy collections are prone to N+1 query issues.
|
||||
====
|
|
@ -0,0 +1,47 @@
|
|||
SELECT
|
||||
max(order_id) + 1
|
||||
FROM
|
||||
Employee
|
||||
WHERE
|
||||
department_id = ?
|
||||
|
||||
-- binding parameter [1] as [BIGINT] - [1]
|
||||
|
||||
SELECT
|
||||
e.id as id1_1_0_,
|
||||
e.department_id as departme3_1_0_,
|
||||
e.username as username2_1_0_
|
||||
FROM
|
||||
Employee e
|
||||
WHERE
|
||||
e.department_id=?
|
||||
AND e.order_id=?
|
||||
|
||||
-- binding parameter [1] as [BIGINT] - [1]
|
||||
-- binding parameter [2] as [INTEGER] - [0]
|
||||
|
||||
SELECT
|
||||
e.id as id1_1_0_,
|
||||
e.department_id as departme3_1_0_,
|
||||
e.username as username2_1_0_
|
||||
FROM
|
||||
Employee e
|
||||
WHERE
|
||||
e.department_id=?
|
||||
AND e.order_id=?
|
||||
|
||||
-- binding parameter [1] as [BIGINT] - [1]
|
||||
-- binding parameter [2] as [INTEGER] - [1]
|
||||
|
||||
SELECT
|
||||
e.id as id1_1_0_,
|
||||
e.department_id as departme3_1_0_,
|
||||
e.username as username2_1_0_
|
||||
FROM
|
||||
Employee e
|
||||
WHERE
|
||||
e.department_id=?
|
||||
AND e.order_id=?
|
||||
|
||||
-- binding parameter [1] as [BIGINT] - [1]
|
||||
-- binding parameter [2] as [INTEGER] - [2]
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.userguide.fetching;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.OrderColumn;
|
||||
|
||||
import org.hibernate.annotations.LazyCollection;
|
||||
import org.hibernate.annotations.LazyCollectionOption;
|
||||
import org.hibernate.annotations.NaturalId;
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class LazyCollectionTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
private static final Logger log = Logger.getLogger( LazyCollectionTest.class );
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Department.class,
|
||||
Employee.class,
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
//tag::fetching-LazyCollection-persist-example[]
|
||||
Department department = new Department();
|
||||
department.setId( 1L );
|
||||
entityManager.persist( department );
|
||||
|
||||
for (long i = 1; i <= 3; i++ ) {
|
||||
Employee employee = new Employee();
|
||||
employee.setId( i );
|
||||
employee.setUsername( String.format( "user_%d", i ) );
|
||||
department.addEmployee(employee);
|
||||
}
|
||||
//end::fetching-LazyCollection-persist-example[]
|
||||
} );
|
||||
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
//tag::fetching-LazyCollection-select-example[]
|
||||
Department department = entityManager.find(Department.class, 1L);
|
||||
|
||||
int employeeCount = department.getEmployees().size();
|
||||
|
||||
for(int i = 0; i < employeeCount; i++ ) {
|
||||
log.infof( "Fetched employee: %s", department.getEmployees().get( i ).getUsername());
|
||||
}
|
||||
//end::fetching-LazyCollection-select-example[]
|
||||
} );
|
||||
}
|
||||
|
||||
//tag::fetching-LazyCollection-domain-model-example[]
|
||||
@Entity(name = "Department")
|
||||
public static class Department {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@OneToMany(mappedBy = "department", cascade = CascadeType.ALL)
|
||||
@OrderColumn(name = "order_id")
|
||||
@LazyCollection( LazyCollectionOption.EXTRA )
|
||||
private List<Employee> employees = new ArrayList<>();
|
||||
|
||||
//Getters and setters omitted for brevity
|
||||
|
||||
//end::fetching-LazyCollection-domain-model-example[]
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public List<Employee> getEmployees() {
|
||||
return employees;
|
||||
}
|
||||
|
||||
public void setEmployees(List<Employee> employees) {
|
||||
this.employees = employees;
|
||||
}
|
||||
|
||||
public void addEmployee(Employee employee) {
|
||||
this.employees.add( employee );
|
||||
employee.setDepartment( this );
|
||||
}
|
||||
//tag::fetching-LazyCollection-domain-model-example[]
|
||||
}
|
||||
|
||||
@Entity(name = "Employee")
|
||||
public static class Employee {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@NaturalId
|
||||
private String username;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
private Department department;
|
||||
|
||||
//Getters and setters omitted for brevity
|
||||
|
||||
//end::fetching-LazyCollection-domain-model-example[]
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public Department getDepartment() {
|
||||
return department;
|
||||
}
|
||||
|
||||
public void setDepartment(Department department) {
|
||||
this.department = department;
|
||||
}
|
||||
//tag::fetching-LazyCollection-domain-model-example[]
|
||||
}
|
||||
//end::fetching-LazyCollection-domain-model-example[]
|
||||
}
|
Loading…
Reference in New Issue