JPA lazy at simple byte[] field level
Asked Answered
M

4

10

Unfortunately the code below does not work. Image is always retrieved!

@Entity
public Car implements Serializable {
    ...
    @Basic(fetch = FetchType.LAZY) //Neither with @Lob
    private byte[] image;
    ...
}

SETUP: JPA 2.0 / Hibernate 3.5 / MySQL 5.5

Moral answered 26/10, 2011 at 11:58 Comment(0)
T
3

Remember that the JPA provider is not required to fetch the data lazily when you specify it so. It's a hint and not a requirement.

JPA Specification 2.0 11.1.6

The EAGER strategy is a requirement on the persistence provider runtime that data must be eagerly fetched. The LAZY strategy is a hint to the persistence provider runtime that data should be fetched lazily when it is first accessed. The implementation is permitted to eagerly fetch data for which the LAZY strategy hint has been specified. In particular, lazy fetching might only be available for Basic mappings for which property-based access is used.

Taima answered 26/10, 2011 at 12:8 Comment(6)
Thank you Pedro! So am i lost?Moral
Pedro, I really think this is a Hibernate bug (it wouldn't be the first one they do on their JPA implementation). Check out this question: #2605977. The guy basicaly has the same issue as you, suggested solution: make a one to one mapping between you entity (sans the image) and another entity containing only the byte[] and make that association lazyBritain
@AndreiBodnarescu of course it might be a Hibernate bug, but nevertheless you cannot assume that the JPA provider will lazily load your data. In my opinion if your logic depends on such feature it should be well documented as you might be surprised when changing the JPA provider.Taima
Agreed, but what I think is happening here is more of a "hibernate don't do lazy load because of bug" rather then "hibernate don't do lazy load because of high respect for the JPA specs which say that it's just a hint". I think if you try to lazy load it via association the hibernate will actually go into "lazy load as per JPA specs" and chose to actually lazy load.Britain
Ok, so CellinHc, could you try the way @AndreiBodnarescu suggests? Also you can check if moving from field-based access to property-based access will change a thing.Taima
I create a wrapper mapped class for image and did @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)... Everything is working nice... It's not perfect but...Moral
P
3

The trick how to achive this described in this topic: http://justonjava.blogspot.it/2010/09/lazy-one-to-one-and-one-to-many.html

I've cheched it on Hibernate v.4.3.5 and JPA v.1.5.0, PostgreSQL 9.3. Worked like a charm. Example:

public class Attachment implements FieldHandled{
    @Transient
    private FieldHandler fieldHandler;
...
...
    @Lob
    @Column(name=CONTENT, nullable=false)
    @Basic(fetch = FetchType.LAZY, optional = false)
    private byte[] content;

...
...
    public byte[] getContent() {
    if(fieldHandler!=null){
        return (byte[])fieldHandler.readObject(this, "content", content);
    }
    return content;
    }

    public void setContent(byte[] content) {
    if(fieldHandler!=null){
        fieldHandler.writeObject(this, "content", this.content, content);
        return;
    }
    this.content = content;
    }

}

Note: If you are using CGLib, implement net.sf.cglib.transform.impl.InterceptFieldEnabled instead of FieldHandled, with the same approach.

Polanco answered 7/11, 2014 at 16:35 Comment(0)
B
0

I remember this being a question a while back (circa 2007): namely why byte arrays are eagerly fetched even tho they are declared as lazy. Apparently the Hibernate guys still haven't fixed this issue.

Here's some viable alternatives:

Fist , try annotating your field with @Lob as well and see if that works as expected.

Second, replace your byte[] with java.sql.Blob, it has convenience methods for setting and getting the actual byte array so it won't be a big refactoring, and this should actually solve the lazy loading issue:

http://download.oracle.com/javase/1.4.2/docs/api/java/sql/Blob.html

Britain answered 26/10, 2011 at 12:4 Comment(1)
Thank you Andrei, but those approaches don't work for me. BIG PROBLEMS! @Lob @Basic(fetch = FetchType.LAZY) Blob private byte[] image; EntityManager can't persist this property... persist all fields and image stays null. I'm using the concrete class SerialBlobMoral
H
0

To my knowledge lazy loading is only possible when you have a @OneToMany relation (unless you use class weaving). This at least is how EclipseLink explains it http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Mapping/Basic_Mappings/Lazy_Basics, and it makes sense from a java language perspective. When you have

@OneToMany (fetch = FetchType.LAZY)
Collection<Employee> employees;

Collection is an interface so JPA can easily use its own Collections implementation that loads data lazily when you start iterating through it. If you have an object with a field of type byte[] it value is either null or it contains all the data, this is how Java works. The only way to circumven this is to use class weaving and create byte-code that looks like a byte array, but doesn't contain any data until you access it.

Hisakohisbe answered 12/10, 2012 at 16:20 Comment(1)
It seems that the OP is using Hibernate and not EclipseLinkPreconscious

© 2022 - 2024 — McMap. All rights reserved.