I believe there is bug that ignores FetchType.EAGER on native queries. I went back to a previous version of boot and works as expected.

Conditions:

  • Having property spring.jpa.open-in-view=false
  • No@Transactional wrapper
  • Two entities with a relation marked as fetch = EAGER
  • One jpql query that fetches all the entities
  • One native query that fetches all the entitites

Expected result

Both queries successfully return the entitites.

Result

The jqpl query honors the fetch type and successfully return the entities The native query produces:

jakarta.servlet.ServletException: Request processing failed: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.example.demo.model.Parent.child: could not initialize proxy - no Session

Supporting information

I've created an example of the different behaviour in boot version 3.0.0 vs 2.1.9.RELEASE : https://github.com/domgom/hibernate-fetch-boot-2-3

Affected Boot version under test:
  3.0.0
System:
  Apple M1 Max
OS: 
  macOS Ventura 13.1
JDK:
  openjdk 19.0.1 2022-10-18
  OpenJDK Runtime Environment Homebrew (build 19.0.1)
  OpenJDK 64-Bit Server VM Homebrew (build 19.0.1, mixed mode, sharing)

Comment From: wilkinsona

Thanks for the sample.

This appears to be a regression in Hibernate as the same problem occurs when calling the EntityManager directly:

package com.example.demo.controller;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import com.example.demo.model.Parent;

import jakarta.persistence.EntityManager;
import jakarta.persistence.Query;
import jakarta.persistence.TypedQuery;

@Controller
@RequestMapping("/parent")
public class ParentController {

    private static final Logger log = LoggerFactory.getLogger(ParentController.class);

    private final EntityManager entityManager;

    public ParentController(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    @GetMapping
    @SuppressWarnings("unchecked")
    public ResponseEntity<String> getParent() throws InterruptedException {

        log.info("> JPQL");
        TypedQuery<Parent> query = this.entityManager.createQuery("SELECT p FROM Parent p", Parent.class);
        query.getResultList().forEach((p) -> System.out.println(p + " " + p.getChild()));        

        log.info("> Native");
        Query nativeQuery = this.entityManager.createNativeQuery("SELECT * FROM Parent", Parent.class);
        ((List<Parent>)nativeQuery.getResultList()).forEach((p) -> System.out.println(p + " " + p.getChild()));

        return ResponseEntity.ok("Cool");
    }
}

@domgom You may want to open a Hibernate JIRA issue for this. If you do so, I would recommend stripping your sample down as much as possible, ideally removing Spring from it entirely so that it's as focussed as possible.

Comment From: domgom

Linking just for reference: https://hibernate.atlassian.net/browse/HHH-16191

Comment From: wimhuizinga

I'm not a Hibernate expert, but what works for me is to add a @NamedEntityGraph and add it to the attributeNodes for the @ManyToOne entity I want to load.