I am running a search with hibernate search in the Spring Boot environment but when executing the query I get failed to lazily initialize a collection of role.
I have tried all the variants exposed in the other similar questions. My entity has a many to many relationship with two others.
@Entity
@Indexed
public class A extends AbstractAuditableEntity<D, Long> implements
Serializable {
@Column
@Field(index = Index.YES, analyze = Analyze.YES, store =
Store.NO)
private String name;
@ManyToMany(mappedBy = "a")
@IndexedEmbedded
private List<B> b;
@OneToMany(mappedBy = "a")
@IndexedEmbedded
private List<C> c;
}
My controller class:
@RestController
public class SearchController {
@Autowired
private SearchService searchService;
@GetMapping("/search")
public ResponseEntity<?> search(@RequestParam String terms){
List<A> aList = searchService.search(terms);
return aList.isEmpty() ? new ResponseEntity<>
(HttpStatus.NO_CONTENT) : new ResponseEntity<>(aList,
HttpStatus.OK);
}
}
My service class:
@Service
public class SearchService {
@Autowired
private aRepository aRepository;
@Transactional
public List<A> search(String terms) {
return aRepository.search(terms);
}
}
My repository layer:
public interface ARepository extends JpaRepository<A, Long>,
IndexSearchARepository {
}
Extended interface:
@Transactional
public interface IndexSearchARepository {
public List<A> search(String terms);
}
And the good part, the implementation:
public class IndexSearchARepositoryImpl implements
IndexSearchARepository {
private final EntityManager entityManager;
@Autowired
public IndexSearchARepositoryImpl(EntityManager entityManager)
{
this.entityManager = entityManager;
}
@Override
@Transactional
public List<A> search(String terms) {
FullTextEntityManager fullTextEntityManager =
Search.getFullTextEntityManager(entityManager);
QueryBuilder queryBuilder =
fullTextEntityManager.getSearchFactory().buildQueryBuilder()
.forEntity(A.class).get();
Query luceneQuery = queryBuilder
.keyword()
.fuzzy()
.withEditDistanceUpTo(1)
.withPrefixLength(1)
.onFields("name")
.matching(terms)
.createQuery();
javax.persistence.Query jpaQuery = fullTextEntityManager
.createFullTextQuery(luceneQuery, A.class);
List<A> aList = null;
try {
aList = jpaQuery.getResultList();
} catch (NoResultException nre) {
log.debug(nre.getMessage());
}
return aList;
}
}
Highlight that if I put a breakpoint and go step by step it does not throw the exception. I do not know when try to access the relationship that apparently the session closes before, @Transactional should not handle this?
Output:
"message": "Could not write JSON: failed to lazily initialize a
collection of role: com.xxxx.entity.A.b,
could not initialize proxy - no Session
Hibernate Session exists within method with @Transactional
.
Passing entity outside Service class is a bad practise because session is being closed after leaving your search
method. On the other hand your entity contains lazy initialised collections, which cannot be pulled once session is closed.
The good practise is to map entity onto transport object and return those transport objects outside (not raw entities).