539 words

Mapped (Inverse) LAZY @OneToMany vs. Unmapped LAZY @OneToMany

#1
2012-03-14 01:37

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);
        }
    }
}
--- Webel IT Australia, "The Elements of the Web", Specialists in model-based UML, SysML, Enterprise Java, XML, and Drupal CMS web engineering. Dr Darren Kelly, BSc, PhD, https://www.webel.com.au
webel
webel's picture
Joined on 2011-05-27
User Post #44
#2
2012-03-14 05:23

LAZY in JPA is a hint.

If your code is enhanced (as always recommended), for example, you run this test case by:

java -javaagent:objectdb.jar com.greensoft.objectdb.test.console.TestLazyOneToMany

Then ObjectDB follow the hint and the output is:

a.listA_mapped:null
a.listB_unmapped:[]

If the code is not enhanced, ObjectDB has to keep a snapshot of the entity object when it is loaded in order to identify changes on commit. In previous versions of ObjectDB the entity snapshot didn't include inverse (mapped by) fields, but currently it does (it may be changed again in future versions), so currently inverse relationships are always loaded eagerly in entity classes that are not enhanced.

ObjectDB Support
ObjectDB - Fast Object Database for Java (JPA/JDO)
support
support's picture
Joined on 2010-05-03
User Post #972
#3
2012-03-15 06:43

Thanks for your explanation. I was able to confirm the result with enhancer on. I am curious to know (it's purely an academic question) why the mapped list gives null and the unmapped list gives an empty list [], when DO_VIEW_BEFORE_CLOSE = false.

--- Webel IT Australia, "The Elements of the Web", Specialists in model-based UML, SysML, Enterprise Java, XML, and Drupal CMS web engineering. Dr Darren Kelly, BSc, PhD, https://www.webel.com.au
webel
webel's picture
Joined on 2011-05-27
User Post #45
#4
2012-03-16 08:43

Actually there is no good reason for this. Build 2.3.7_05 removes this difference by setting unloaded collections to null on detachment, for both mapped an unmapped collections.

ObjectDB Support
ObjectDB - Fast Object Database for Java (JPA/JDO)
support
support's picture
Joined on 2010-05-03
User Post #977

Post Reply

Please read carefully the posting instructions - before posting to the ObjectDB website.

  • You may have to disable pop up blocking in order to use the toolbar (e.g. in Chrome).
  • Use ctrl + right click to open the browser context menu in the editing area (e.g. for using a browser spell checker).
  • To insert formatted lines (e.g. Java code, stack trace) - select a style in the toolbar and then insert the text in the new created block.
  • Avoid overflow of published source code examples by breaking long lines.
  • You may mark in paragraph code words (e.g. class names) with the code style (can be applied by ctrl + D).
  • Long stack traces (> 50 lines) and complex source examples (> 100 lines) should be posted as attachments.
Attachments:
Maximum file size: 32 MB
Cancel