13

I have next error: nested exception is org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.example.Model.entities, could not initialize proxy - no Session

My Model entity:

class Model {
...
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "model", orphanRemoval = true)
    @Cascade(CascadeType.ALL)
    @Fetch(value = FetchMode.SUBSELECT)
    public Set<Entity> getEntities() {
        return entities;
    }

    public void addEntity(Entity entity) {
        entity.setModel(this);
        entities.add(entity);
    }

}

And I have a service class:

@Service
@Transactional
class ServiceImpl implements Service {
    @Override
    public void process(Model model) {
        ...
        model.addEntity(createEntity());
        ...
    }
}

I'm calling service from another service method:

@Override
@JmsListener(destination = "listener")
public void handle(final Message message) throws Exception {
    Model model = modelService.getById(message.getModelId());
    serviceImpl.process(model);
    modelService.update(model);
}

But when I'm trying to call this method I'm getting exception on line entities.add(entity); also the same exception occurs when I'm calling getEntities() on model . I've checked transaction manager and it's configured correctly and transaction exists on this step. Also I've checked tons of answers on stackoverflow connected to this exception but nothing useful.

What could be the cause of it?

Maciej Kowalski
  • 25,605
  • 12
  • 54
  • 63
Orest
  • 6,548
  • 10
  • 54
  • 84
  • When you say "_transaction exists on this step_" you mean that you have checked that a transaction is really open, like using http://stackoverflow.com/a/42584751/3517383? – gabrielgiussi Mar 21 '17 at 11:34
  • @gabrielgiussi yes – Orest Mar 21 '17 at 11:35
  • Is entity a new object? If it's the case, you have to save the entity object first in the database and then you can add it in the list of entities. – Dimitri Mar 21 '17 at 13:32
  • I guess you are wrong, actually calling model.getEntities() gives me the same error about lazyinitialization – Orest Mar 21 '17 at 13:41

2 Answers2

9

It seems that model is a detached entity.

Try to merge and perform operations on a merge instance:

@Override
public void process(Model model) {
     ...
    Model mergedModel = session.merge(model);

    mergedModel.addEntity(createEntity());
    ...
}
Maciej Kowalski
  • 25,605
  • 12
  • 54
  • 63
  • Indeed, or open the transaction in an initial service that invokes all the other services. – gabrielgiussi Mar 21 '17 at 11:39
  • 1
    Actually I don't want to use session object. Just before calling process I'm doing modelService.getModelById(modelId); and it returns me object from database – Orest Mar 21 '17 at 13:19
  • 2
    Ok but that is done i assume in a separate transaction.. once you call process method the model is already a detached entity and persistence provider does not manage it anymore. You have to merge it back. Or simply make the query inside of the process method. – Maciej Kowalski Mar 21 '17 at 13:45
  • Thanks your answer helped. Added query to my process method – Orest Mar 21 '17 at 14:14
7

So as @Maciej Kowalski mentioned after first @Transactional read of my model it's already in deatached state and call to get entities from another @Transactional method failed with LazyInitializationException.

I've changed my service a bit to get model from database in the same transaction:

@Service
@Transactional
class ServiceImpl implements Service {
    @Override
    public void process(long modelId) {
        ...
        Model model = modelDao.get(modelId);
        model.addEntity(createEntity());
        ...
    }
}

Now everything works as expected.

Orest
  • 6,548
  • 10
  • 54
  • 84