Olivier Boissé
Olivier Boissé

Reputation: 18173

why the lazy collection is loaded

I have a Project entity with a oneToMany relationship with Event entity

public class Project {
   ....

   @OneToMany(mappedBy = "dossier", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
   private List<Event> events;

}

I have a ProjectService class

@Service
@Transactional
public class ProjectService {

    public List<Project> findAll() {
        return (List<Project>) projectRepository.findAll();
    }
}

And a ProjectController

@RestController
@RequestMapping(value = "/projects")
public class ProjectController {

    @RequestMapping(method= RequestMethod.GET)
    public List<Project> getAllProject() {
        return projectService.findAll();
    }
}

In my client code I saw that the events of the projects are loaded and I don't understand why.

I expected that at the end of the transaction of the method findAll in DossierService, the entities will be detached. Obviously my entities are still attached as the events are retrieved during the jackson serialization in my controller.

Upvotes: 4

Views: 2341

Answers (3)

Arnaud Denoyelle
Arnaud Denoyelle

Reputation: 31283

Project.events is by default lazy-loaded because it is a OneToMany relationship.

It does not mean that Project.events is not loaded. It means that it will be loaded as soon as Project.getEvents() is called.

This occurs at the JSON serialization (when ProjectController.getAllProject() returns its response).

In order to prevent that, there are 2 ways :

  • Either you explicitly call project.setEvents(null) (or an empty list) on every project returned by ProjectService.
  • Or you add a @JsonIgnore annotation on Project.events.

EDIT: if you are using spring-boot, an OpenEntityManagerInViewInterceptor is registered by default :

Spring web request interceptor that binds a JPA EntityManager to the thread for the entire processing of the request. Intended for the "Open EntityManager in View" pattern, i.e. to allow for lazy loading in web views despite the original transactions already being completed.

You can disable this behavior by adding this line to application.properties :

spring.jpa.open-in-view=false

With this configuration, calling the getter outside of the hibernate session will cause a LazyInitializationException.

Upvotes: 8

Naros
Naros

Reputation: 21153

There are two possibilities:

  1. An OpenSessionInView or OpenEntityManagerInView bean has been defined. This type of bean causes the Session or EntityManager, respectively, to be opened at the time the controller is invoked and remains open until the controller's body has been serialized.

    It is typically considered acceptable behavior in demo/small applications, but it's highly frowned upon in larger more complex applications as your queries should return fully initialized entities required for your view, controller, or logic.

  2. The JSON library has a hibernate addon enabled where it is capable of reattaching and hydrating the entity during the serialization process.

Otherwise, the default behavior that you expect where the Session/EntityManager has closed and the entity is detached once it's returned by the service is accurate. The expected behavior would be a LazyInitializationException otherwise.

Upvotes: 1

Yannick Kirschhoffer
Yannick Kirschhoffer

Reputation: 96

Your entities are still attached until:

  • You ask the entity manager to clear the persistence context using entityManager.clear()
  • You ask the entity manager to detach your entity using entityManager.detach(project) for every project.

But if you know that your events will be loaded most of the time, you should then consider using FetchType.EAGER so that everything would be fetched at once.

Upvotes: 0

Related Questions