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); } } }