Usually we are passing initStrategies to the service methods in order to initialize associated entities. In this case this way would not be appropriate since the method causing the LIE is member method of the Class which is being used in a select new {constructor}
expression.
Therefore the proper most solution for this problem would be to initialize the rank.vocabulary directly in the TaxonNameDaoHibernateImpl
.
This however is not (yet?) working due to a specific interpretation of the JPA language specs: https://hibernate.atlassian.net/browse/HHH-3345 so the following code will not work:
private StringBuilder prepareFindTaxonNameParts(boolean doCount, Optional<String> genusOrUninomial,
Optional<String> infraGenericEpithet, Optional<String> specificEpithet,
Optional<String> infraSpecificEpithet, Rank rank, Collection<UUID> excludedNamesUuids) {
StringBuilder hql = new StringBuilder();
if(doCount){
hql.append("select count(n.id) ");
} else {
hql.append("select new eu.etaxonomy.cdm.persistence.dto.TaxonNameParts(n.id, n.uuid, n.rank, n.genusOrUninomial, n.infraGenericEpithet, n.specificEpithet, n.infraSpecificEpithet) ");
}
hql.append("from TaxonName n ");
if(!doCount){
// >>>>>>>>>>>>>> need to initialize the ranks with vocabulary to avoid LIEs in TaxonNameParts.rankSpecificNamePart() see #9483
// >>>>>>>>>>>>>> This will not work due to HHH-3345
hql.append("left join fetch n.rank as r left join fetch r.vocabulary as v ");
}
hql.append("where 1 = 1 ");
if(rank != null){
hql.append("and n.rank = :rank ");
}
if(excludedNamesUuids != null && excludedNamesUuids.size() > 0){
hql.append("and n.uuid not in ( :excludedNamesUuids ) ");
}
addFieldPredicate(hql, "n.genusOrUninomial", genusOrUninomial);
addFieldPredicate(hql, "n.infraGenericEpithet", infraGenericEpithet);
addFieldPredicate(hql, "n.specificEpithet", specificEpithet);
addFieldPredicate(hql, "n.infraSpecificEpithet", infraSpecificEpithet);
return hql;
}
Therefore I decided to initialize the rank.vocabulary in the constructor:
public TaxonNameParts(Integer taxonNameId, UUID taxonNameUuid, Rank rank, String genusOrUninomial, String infraGenericEpithet,
String specificEpithet, String infraSpecificEpithet) {
super();
this.taxonNameId = taxonNameId;
this.taxonNameUuid = taxonNameUuid;
this.rank = rank;
if(rank != null) {
HibernateBeanInitializer.initialize(rank.getVocabulary());
}
this.genusOrUninomial = genusOrUninomial;
this.infraGenericEpithet = infraGenericEpithet;
this.specificEpithet = specificEpithet;
this.infraSpecificEpithet = infraSpecificEpithet;
}