javax.persistence.PersistenceUtil.isLoaded() methods can be used to determine the load state of an entity or entity attributes.
From JSR-338:
An entity is considered to be loaded if all attributes with FetchType.EAGER - whether explicitly specified or by default - (including relationship and other collection-valued attributes) have been loaded from the database or assigned by the application. Attributes with FetchType.LAZY may or may not have been loaded.
The instance of the PersistenceUtil interface can be obtained by the javax.persistence.Persistence.getPersistenceUtil() method.
Note that, instead of using PersistenceUtil.isLoaded() we can also use PersistenceUnitUtil.isLoaded() . The instance of PersistenceUnitUtil can be retrieved by EntityManagerFactory.getPersistenceUnitUtil() instance method.
PersistenceUnitUtil is a sub interface of PersistenceUtil .
Examples
The Entities
@Entity
public class Employee {
@Id
@GeneratedValue
private Integer id;
private String name;
private String department;
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<Phone> phones;
public Employee() {
}
public Employee(String name, String department, Phone... phones) {
this.name = name;
this.department = department;
this.phones = Arrays.asList(phones);
}
.............
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", name='" + name + '\'' +
", department='" + department + '\'' +
'}';
}
}
@Entity
public class Phone {
@Id
@GeneratedValue
private int id;
private String number;
private String type;
public static Phone cell(String number) {
Phone p = new Phone();
p.number = number;
p.type = "cell";
return p;
}
public static Phone work(String number) {
Phone p = new Phone();
p.number = number;
p.type = "work";
return p;
}
.............
@Override
public String toString() {
return "Phone{" +
"id=" + id +
", number='" + number + '\'' +
", type='" + type + '\'' +
'}';
}
}
Using PersistenceUtil.isLoaded() methods
Before and after Persisting
public class LoadStateWithPersist {
private static EntityManagerFactory entityManagerFactory =
Persistence.createEntityManagerFactory("example-unit");
public static void main(String[] args) {
try {
persistEmployee();
} finally {
entityManagerFactory.close();
}
}
public static void persistEmployee() {
Employee employee = new Employee("Joe", "IT",
Phone.cell("111-111-1111"), Phone.work("222-222-2222"));
printLoadState("New Entity", employee);
EntityManager em = entityManagerFactory.createEntityManager();
em.getTransaction().begin();
em.persist(employee);
printLoadState("After persisting", employee);
em.getTransaction().commit();
em.close();
printLoadState("Detach entity after EntityManger.close()", employee);
}
private static void printLoadState(String msg, Employee employee) {
System.out.printf("-- %s --%n", msg);
PersistenceUtil pu = Persistence.getPersistenceUtil();
boolean employeeLoaded = pu.isLoaded(employee);
System.out.printf("employee loaded: %s%n", employeeLoaded);
boolean phonesLoaded = pu.isLoaded(employee, "phones");
System.out.printf(" phones loaded: %s%n", phonesLoaded);
}
} -- New Entity -- employee loaded: true phones loaded: true -- After persisting -- employee loaded: true phones loaded: true -- Detach entity after EntityManger.close() -- employee loaded: true phones loaded: true
Retrieving entity by find()
EntityManager em = entityManagerFactory.createEntityManager();
Employee employee = em.find(Employee.class, 1);
printLoadState("After find()", employee);
//accessing phones via Phone.toString()
System.out.println("Accessing phones: " + employee.getPhones());
printLoadState("After accessing phones", employee);
em.close();
-- After find() -- employee loaded: true phones loaded: false --------------- Accessing phones:[Phone{id=2, number='111-111-1111', type='cell'}, Phone{id=3, number='222-222-2222', type='work'}] -- After accessing phones -- employee loaded: true phones loaded: true ---------------
As seen in above output, just calling find() method marks employee entity as loaded, that's because find() method will initialize all eager fields. As 'phones' field is declared to be lazy, it is only loaded upon first access. This behavior is same when the entity is loaded via JPQL query 'select t from Employee t' (an example is included in project browser below).
Retrieving entity by getReference()
EntityManager em = entityManagerFactory.createEntityManager();
Employee employee = em.getReference(Employee.class, 1);
printLoadState("After finding by getReference()", employee);
//accessing department field
System.out.println("Accessing employee.department: " + employee.getDepartment());
printLoadState("After accessing employee.department field", employee);
//accessing phones field via Phones.toString() method
System.out.println("Accessing employee.phones: " + employee.getPhones());
printLoadState("After accessing employee.phones field", employee);
em.close();
-- After finding by getReference() -- employee loaded: false phones loaded: false --------------- Accessing employee.department: IT -- After accessing employee.department field -- employee loaded: true phones loaded: false --------------- Accessing employee.phones: [Phone{id=2, number='111-111-1111', type='cell'}, Phone{id=3, number='222-222-2222', type='work'}] -- After accessing employee.phones field -- employee loaded: true phones loaded: true ---------------
As seen in above output, both the parent and it's lazy field (phones) are unloaded. That's because getReference() returns an uninitialized proxy of the entity (tutorial here). After accessing department field, the state of employee entity became 'loaded' that's because all non lazy fields (eager fields) had been loaded at that point. As 'phones' field is declared to be fetched lazily, it is only loaded upon first access (just like last find() example)
Example ProjectDependencies and Technologies Used: - h2 1.4.196: H2 Database Engine.
- hibernate-core 5.2.10.Final: The core O/RM functionality as provided by Hibernate.
Implements javax.persistence:javax.persistence-api version 2.1 - JDK 1.8
- Maven 3.3.9
|