HHH-11186 - Add examples for all Hibernate annotations

Document more annotations:

- @LazyCollection
This commit is contained in:
Vlad Mihalcea 2016-12-05 17:30:28 +02:00
parent f8d366e749
commit ab9016306b
4 changed files with 274 additions and 0 deletions

View File

@ -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`

View File

@ -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.
====

View File

@ -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]

View File

@ -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[]
}