4

I have an entity graph defined in my Person entity. When I declare the phone attribute as an attribute node, a join clause is created and only one select is executed, as expected. But when I remove the phone attribute from the entity graph, the phone field is still loaded, but now with a new select query for each Person retrivied. Is it possible to ignore an attribute in a particular EntityGraph?

Person Entity:

@Entity
@Table(name = "person")
@NamedEntityGraph(
    name = Person.PERSON_LAZY,
    attributeNodes = {}
)
public class Person {

    public static final String Person_LAZY = "person.lazy";

    @Id
    @Column(name = "id")
    private Long id;

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

    @JoinColumn(name = "phone")
    @ManyToOne
    private Phone phone;
}

PersonRepository:

@Repository
public interface PersonRepository extends JpaRepository<Person, Long> {

    @EntityGraph(value = Person.PERSON_LAZY, type = EntityGraphType.FETCH)
    @Query("SELECT p FROM Person p")
    public List<Person> findAllLazy();  
}
dinhokz
  • 895
  • 15
  • 36

1 Answers1

3

Short answer, no. Not possible with entity graphs or by any other means.

@ManyToOne relations are eagerly loaded by default. You have to make it lazy to prevent it from being loaded in whatever way.

The general advice is that since you can load lazy relations eagerly, but you can't load eager relations lazily, you should favor lazy for everything just in case.

And yes, this includes entity graphs and all other possible tricks. If a relation is eager either by default or explicitly, it can never be lazy. This was apparently a design choice/implementation detail even with entity graphs, but with no plan to change it.

Kayaman
  • 72,141
  • 5
  • 83
  • 121
  • Can I set a default EntityGraph? So all my queries will use it? – dinhokz Mar 26 '18 at 19:14
  • Possibly, but did you understand that you can't convert an eager relationship to a lazy with an entity graph? You have to set it to `FetchType.LAZY` explicitly. – Kayaman Mar 26 '18 at 19:15
  • The application is already using this entity with eager fetch type. I thought I could keep the Eager fetch type and create a lazy EntityGraph, according to documentation it would be possible with the FETCH strategy. "You specify FETCH as your strategy by importing javax.persistence.fetchgraph in the file containing the entity. In this case, all attributes specified in your entity graph will be treated as FetchType.EAGER, and all attributes not specified will be treated as FetchType.LAZY" – dinhokz Mar 26 '18 at 19:24
  • 1
    I know it's using it with eager fetch type. That's what my answer says. Now the last time I was solving this problem (maybe 1½ years ago) the conclusion was that there's no way to get back to lazy from eager, even though the documentation was suggesting that. I don't remember if it was Hibernate's implementation detail and whether it has changed, but based on my earlier detective work you can't have what you want. I'd be happy to be proved wrong though. I was quite disappointed when I found out it can't be done. – Kayaman Mar 26 '18 at 19:30
  • It seems that you are right, I can't make the relationship Lazy and optionally Eager. I'm also disappointed with the documentation and implementation "fetch profiles" would fit very well in this situation. Thanks for the answer. – dinhokz Mar 27 '18 at 20:29