Problem with @Basic(fetch = FetchType.LAZY)

#1

I have a class where two fields are annotated with @Basic(fetch = FetchType.LAZY) due to them containing quite long Strings and me loading ALL entities of the database on application startup (swing app). Yet they don't seem to be fetched lazily.

This class should hopefully demonstrate the problem:

import javax.persistence.*;

@Entity
public class Sample {
    private String title;
    @Basic(fetch = FetchType.LAZY)
    private String description;
    @Basic(fetch = FetchType.LAZY)
    private String code;

    public Sample() {
    }

    public Sample(String title, String description, String code) {
        this.title = title;
        this.description = description;
        this.code = code;
    }

    //getters and setters

    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("$objectdb/db/sample.odb");
        EntityManager em = emf.createEntityManager();
        Sample sample = new Sample("Title", "long'ish description", "really LONG code string");
        em.getTransaction().begin();
        em.persist(sample);
        em.getTransaction().commit();
        em.flush();
        em.close();
        emf.close();
        //Close everything and reopen to make sure no cache of the description / code is left behind
        emf = Persistence.createEntityManagerFactory("$objectdb/db/sample.odb");
        em = emf.createEntityManager();
        sample = em.createQuery("select s from Sample s", Sample.class).getResultList().get(0);
        em.detach(sample); //just to be sure
        em.close();
        emf.close();

        System.out.println(sample.title);
        System.out.println(sample.description);
        System.out.println(sample.code);
    }
}

I expect a LazyInitializationException on the last 2 println statements, but it just prints the content, meaning both code and description properties must have been loaded on the query, ignoring the fetch = FetchType.LAZY hint.

Am I doing something wrong?
(I am using objectdb-2.3.6_10)

 

tia,

Wim

 

#2

LAZY in JPA (unlike EAGER) is merely a hint, which JPA implementations may ignore.

ObjectDB always loads basic fields eagerly, regardless of the LAZY / EAGER setting.

If you have very large strings that you want to load lazily - keep them in separate entity objects. For example, you can define an entity class, LargeString, with a single String field, setting references to LargeString as LAZY.

Alternatively, you can use queries to retrieve only selected fields. But still keeping the large strings in separate entities may be more efficient, if usually these strings are not required.

 

ObjectDB Support
#3

For example, you can define an entity class, LargeString, with a single String field, setting references to LargeString as LAZY.

 

Okay, I will do just that.

Thanks for the quick response.

 

Wim

#4

So I replaced my original code with

    @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    private LargeString description;
    @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    private LargeString code;

Nothing special about the LargeString class:

import javax.persistence.Entity;

@Entity
public class LargeString {
    private String string;

    public LargeString() {
    }

    public LargeString(String string) {
        this.string = string;
    }

    public String getString() {
        return string;
    }

    public void setString(String string) {
        this.string = string;
    }
}

And unfortunately it just prints both values :(

Both classes attached below.

 

tia,

Wim DC

 

 

#5

LAZY is still a hint. ObjectDB (as other JPA providers) can only load one-to-one relationships lazily when entity classes are enhanced.

ObjectDB Support

Reply