Hibernate ignores fetchgraph
Asked Answered
T

1

9

This is my entity:

public class PersonItem implements Serializable{
    @Id
    @Column(name="col1")
    private String guid;

    @Column(name="col2")
    private String name;

    @Column(name="col3")
    private String surname;

    @Column(name="col4")
    private Date birthDate;
 //+getters and setters
}

This is how I get the list of persons:

Query query = em.createQuery("Select p from PersonItem p WHERE p.guid IN (:guids)");
EntityGraph<PersonItem> eg = em.createEntityGraph(PersonItem.class);
eg.addAttributeNodes("guid");
eg.addAttributeNodes("name");
eg.addAttributeNodes("surname");
query.setHint("javax.persistence.fetchgraph", eg);
query.setParameter("guids", guids);
List<PersonItem> list=query.getResultList();
em.close();
// And now I iterate result AFTER EM CLOSE
....iterate

If I understand fetch graph correcly it must load only those fields, which I specified. However, the field "birthDate" is also loaded. Besides I see that in hibernate sql query 4 columns are selected.

How to fix it? I use hibernate 5.1.0 as JPA provider.

Transcription answered 5/5, 2016 at 15:8 Comment(0)
V
6

Entity graphs are meant to control which relationships (e.g. one-to-one, one-to-many, etc.) are loaded lazily or eagerly. They may not work for loading individual columns (it depends on the provider).

Hibernate has some support for this, but it is fairly difficult to get working, described here. However, they mention the following reticence towards this approach (which I whole-heartedly agree with):

Please note that this is mostly a marketing feature; optimizing row reads is much more important than optimization of column reads.

So I would not recommend going too far down this road until you've confirmed that this is indeed a bottleneck in your application (e.g. this kind of fetch tuning can be a symptom of premature optimization).

UPDATE:

As pointed out, JPA does leave it up to the provider as to whether or not simple columns (non-associations) are lazily fetched.

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.

Starting with Hibernate 5, official support for bytecode enhancement was added and this may allow for lazy attribute fetching.

From the latest Hibernate docs we have:

2.3.2

fetch - FetchType (defaults to EAGER)

Defines whether this attribute should be fetched eagerly or lazily. JPA says that EAGER is a requirement to the provider (Hibernate) that the value should be fetched when the owner is fetched, while LAZY is merely a hint that the value be fetched when the attribute is accessed. Hibernate ignores this setting for basic types unless you are using bytecode enhancement.

And this next snippet that describes the advantages of bytecode enhancement.

Lazy attribute loading

Think of this as partial loading support. Essentially you can tell Hibernate that only part(s) of an entity should be loaded upon fetching from the database and when the other part(s) should be loaded as well. Note that this is very much different from proxy-based idea of lazy loading which is entity-centric where the entity’s state is loaded at once as needed. With bytecode enhancement, individual attributes or groups of attributes are loaded as needed.

Vendetta answered 5/5, 2016 at 18:52 Comment(5)
The link you provided about hibernate 3.3 version. Maybe the things have changed since that time?Transcription
Could you comment this answer - https://mcmap.net/q/1318341/-hibernate-load-entities-with-fields-defined-at-runtime . There the man say that this code works with another jpa provider and this is according to JPA specs.Transcription
It may be supported if you use bytecode enhancement, also, my answer is specific to Hibernate. I agree the JPA spec says that a provider can take either approach. I'll update with relevant references from the latest docs.Vendetta
This is wrong: They are not intended (and do not work for) loading individual columns. I've tested that approach in EclipseLink and it worked as expected. Only three columns were read from the DB.Transcription
I will admit that is wrong and will update my answer. It may work but is not guaranteed to. I've added references to the JPA spec explaining as much.Vendetta

© 2022 - 2024 — McMap. All rights reserved.