Deletion of contained entity whose elementCollection is indexed-embedded in the containing entity leads to LazyInitializationException

Description

Relevant test in Search 5: org.hibernate.search.test.embedded.EmbeddedTest#testEmbeddedIndexing, the very last transaction.

If:

  • An entity A is embedded in an entity B through @IndexedEmbedded on an association B.a

  • Entity A has an @ElementCollection property, A.elementCollection, which is indexed-embedded in B

  • The inverse side of B.a in entity A is named A.b, and that inverse side is lazy, and A is not the owner of that association.

  • Entity A gets loaded in the session, then deleted immediately

Then Hibernate Search will:

  • Receive a PostCollectionRemove event and mark A as updated as a result

  • Receive a deletion event for A and mark A for deletion as a result

  • Resolve the entities that should be reindexed as a result of the update of A

    • Access the association from A to B because elementCollection changed and is embedded in B

    • LazyInitializationException is thrown

In Search 5, we used to have this piece of code in AbstractDocumentBuilder to guard us against this problem:

It does work around the problem, but I'm not sure it is safe. In particular, B could be referencing another entity through this association, say A2, and that other entity would need to be updated following the deletion of B. As far as I can tell, in Search 5 A2 will just become out of sync.

There are multiple solutions:

  1. We could use the same workaround: give the mapper a chance to attempt the initialization of the collection before we proceed, and to return null if the collection cannot be initialized. For example add an initializeOrNull() method to PojoRuntimeIntrospector. But that means accepting that A2 becomes out of sync in the example above.

  2. We could decide not to resolve reindexing upon deletion. Essentially we'd expect associations referencing the deleted entity to be systematically updated, so reindexing will be triggered because of these updates. This is consistent with what we require for association updates. It would be a shame, though, because in many cases we absolutely can resolve reindexing.

  3. We could try to see if the LazyInitializationException being thrown is a bug, and if so fix it in ORM.

  4. We could try to detect this problem at bootstrap time and refuse the mapping unless someone adds @IndexingDependency(reindexOnUpdate = ReindexOnUpdate.NO. For example if we detect an association where one side is Many and lazy, and the other is owner and has CascadeType.REMOVE. But I doubt we can accurately detect all cases.

Environment

None

Activity

Show:
Yoann Rodière
7 days ago

Updated the summary and description after some more investigation.

Assignee

Yoann Rodière

Reporter

Yoann Rodière

Labels

None

Suitable for new contributors

None

Feedback Requested

None

Components

Fix versions

Priority

Major
Configure