Search code examples
hibernatejpalazy-loading

How to initialize LAZY entity several layers deep in JPA?


I have a several level deep relationship:

class Person {
  @Id
  @Column(name = "PERSON_ID")
  private Long personId;

  @OneToMany(fetch = FetchType.EAGER, mappedBy = "person")
  private Set<Parameter> parameters;

  [... various other attributes omitted]
} 

class Parameter {
  @Id
  @Column(name = "PARAMETER_ID")
  private Long personId;

  @ManyToOne(cascade = CascadeType.ALL)
  @JoinColumn(name = "GAME_ID", nullable = false)
  private Game game;

  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "PERSON_ID")
  @JsonIgnore
  private Person person;

  [... various other attributes omitted]
} 

class Game {
  @Id
  @Column(name = "GAME_ID")
  private Long gameId;

  @OneToMany(fetch = FetchType.LAZY, mappedBy = "game") // this is the attribute, that sometimes is required sometimes is not
  private Set<GameRule> gameRules;

  @OneToMany(fetch = FetchType.LAZY, mappedBy = "game")
  @JsonIgnore
  private Set<Parameter> parameters;

  [... various other attributes omitted]
}

class GameRule {
  @Id
  @Column(name = "GAME_RULE_ID")
  private Long gameRuleId;

  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name="GAME_ID", nullable = false)
  @JsonIgnore
  private Game game;

  [... various other attributes omitted]
}

Can anyone tell me how can I "join fetch" with game.gameRules when querying person ? I've tried to create a @NamedEntityGraph on game (with the gameRules attribute), and use it in person's repository findAll with @EntityGraph, but using the entitygraph in person's repository caused an exception Hibernate not being able to find gameRules attribute in person (no surprise).

So how can someone initialize a lazy entity on member level several levels deep? Thanks,


Solution

  • As your relationship is nested in this case you need to use the subgraph and @NamedSubgraph as shown below.

    use graph.person.parameters as graph name in your repository method.

    @NamedEntityGraph(name = "graph.person.parameters", attributeNodes = {
            @NamedAttributeNode(value = "parameters", subgraph = "parameters.game") }, subgraphs = {
                    @NamedSubgraph(name = "parameters.game", attributeNodes = {
                            @NamedAttributeNode(value = "game", subgraph = "game.gameRules") }),
                    @NamedSubgraph(name = "GameRule ", attributeNodes = {
                            @NamedAttributeNode(value = "GameRule ") }) })