Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LazyInitializationException with graphql-spring

I am currently in the middle of migrating my REST-Server to GraphQL (at least partly). Most of the work is done, but i stumbled upon this problem which i seem to be unable to solve: OneToMany relationships in a graphql query, with FetchType.LAZY.

I am using: https://github.com/graphql-java/graphql-spring-boot and https://github.com/graphql-java/graphql-java-tools for the integration.

Here is an example:

Entities:

@Entity
class Show {
   private Long id;
   private String name;

   @OneToMany(mappedBy = "show")
   private List<Competition> competition;
}

@Entity
class Competition {
   private Long id;
   private String name;

   @ManyToOne(fetch = FetchType.LAZY)
   private Show show;
}

Schema:

type Show {
    id: ID!
    name: String!
    competitions: [Competition]
}

type Competition {
    id: ID!
    name: String
}

extend type Query {
    shows : [Show]
}

Resolver:

@Component
public class ShowResolver implements GraphQLQueryResolver {
    @Autowired    
    private ShowRepository showRepository;

    public List<Show> getShows() {
        return ((List<Show>)showRepository.findAll());
    }
}

If i now query the endpoint with this (shorthand) query:

{
  shows {
    id
    name
    competitions {
      id
    }
  }
}

i get:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: Show.competitions, could not initialize proxy - no Session

Now i know why this error happens and what it means, but i don't really know were to apply a fix for this. I don't want to make my entites to eagerly fetch all relations, because that would negate some of the advantages of GraphQL. Any ideas where i might need to look for a solution? Thanks!

like image 798
puelo Avatar asked Dec 30 '17 20:12

puelo


1 Answers

My prefered solution is to have the transaction open until the Servlet sends its response. With this small code change your LazyLoad will work right:

import javax.servlet.Filter;
import org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter;

@SpringBootApplication
public class Application {

  public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
  }

  /**
   * Register the {@link OpenEntityManagerInViewFilter} so that the
   * GraphQL-Servlet can handle lazy loads during execution.
   *
   * @return
   */
  @Bean
  public Filter OpenFilter() {
    return new OpenEntityManagerInViewFilter();
  }

}
like image 186
Jaxt0r Avatar answered Sep 22 '22 13:09

Jaxt0r