In the code example below (also attached) I would like to understand why I am able to print to console a lazy @OneToMany mapped field after a finding entity manager closes. There is a switch DO_VIEW_BEFORE_CLOSE, and when it is true the fields are accessed and output before the finding entity manager closes and as expected both a mapped @OneToMany list and an unmapped @OneToMany list are viewable:
a.listA_mapped:[{A}[4]"ownedElement1", {A}[5]"ownedElement2"]
a.listB_unmapped:[{B}[2]"b1", {B}[3]"b2"]
When I set DO_VIEW_BEFORE_CLOSE false, so that the fields are only accessed after the finding entity manager closes, I can still view a.listA_mapped, whereas a.listB_unmapped is not visible/resolved, as one would expect for LAZY:
a.listA_mapped:[{A}[4]"ownedElement1", {A}[5]"ownedElement2"]
a.listB_unmapped:[]
Note that at no time after the find do I access the other mapping side of the relationship a.a.
Q: Why is the LAZY behaviour different for mapped and unmapped lists ?
package com.greensoft.objectdb.test.console;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.*;
/**
*
* @author Darren Kelly (Webel IT Australia for Greensoft)
*/
public class TestLazyOneToMany {
/**
* If true the view/output of the fields of the entities will be called
* before the relevant finding EntityManager closes.
*/
final static boolean DO_VIEW_BEFORE_CLOSE = true;
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
String $connection = "objectdb:db/TestLazyOneToMany.tmp;drop";
EntityManagerFactory emf =
Persistence.createEntityManagerFactory($connection);
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
A a = new A("aOwner");
a.listA_mapped = new ArrayList<A>();
A aOwnedElement1 = new A("ownedElement1");
aOwnedElement1.a = a;
a.listA_mapped.add(aOwnedElement1);
A aOwnedElement2 = new A("ownedElement2");
aOwnedElement2.a = a;
a.listA_mapped.add(aOwnedElement2);
a.listB_unmapped = new ArrayList<B>();
a.listB_unmapped.add(new B("b1"));
a.listB_unmapped.add(new B("b2"));
em.persist(a);
em.getTransaction().commit();
Long id = a.id;
em.close();
em = emf.createEntityManager();
a = em.find(A.class, id);
if (!DO_VIEW_BEFORE_CLOSE) {
em.close();
}
//Output entities and fields
System.out.println("a.listA_mapped:" + a.listA_mapped);
//gives: '[a.listA_mapped:[{A}[4]"ownedElement1", {A}[5]"ownedElement2"]
System.out.println("a.listB_unmapped:" + a.listB_unmapped);
//gives: '[]' or '[{B}[2]"b1", {B}[3]"b2"]'
if (DO_VIEW_BEFORE_CLOSE) {
em.close();
}
emf.close();
}
@Entity
static public class A {
@Id
@GeneratedValue
Long id;
String name;
public A(String name) {
this.name = name;
}
@Override
public String toString() {
return "{" + getClass().getSimpleName() + "}" + "[" + id + "]\"" + name + "\"";
}
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
A a; //maps: listA_mapped
@OneToMany(fetch = FetchType.LAZY, mappedBy = "a", cascade = CascadeType.ALL)
List<A> listA_mapped;
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
List<B> listB_unmapped;
}
@Entity
static public class B extends A {
public B(String name) {
super(name);
}
}
}