Search code examples
javahibernateentityhqlhibernate-mapping

hibernate query could not resolve property even if the property is there and correct casing


Good day everyone!

I have a method which I use to find the list of Admission and Admission is related to CourseRevision, but it doesn't seem to recognize CourseRevision even if it's in the entity class. Here is the code for finding admissions:

public List<AdmissionDTO> findAdmissions(final String searchPhrase, final String organisationId, final boolean useCourse, final boolean useAdmissionAlternatives, final boolean useApplicationStatusMap, final boolean useTeaching, final boolean useAdmissionSchemaSettings, final boolean useAdmissionSchemaUpload) throws DataAccessException {
    logEntered();
    List<AdmissionDTO> resultsList = new ArrayList<AdmissionDTO>();
if (organisationId == null) {
    log.warn("'organisationId' is NULL or empty!");
    return resultsList;
}

resultsList = new DTOListFetcher<AdmissionDTO, Admission>() {
    @Override
    protected Map<String, Object> getParameters() {
        Map<String, Object> params = new HashMap<String, Object>();
        if (searchPhrase != null && searchPhrase.length() > 0) {
            params.put("searchPhrase", MessageFormat.format("%{0}%", searchPhrase));
        }
        params.put("organisationId", organisationId);
        return params;
    }

    @Override
    protected String getQueryString() {
        String queryString = "from Admission a " + "left join fetch a.courseRevision cr "
                + "left join fetch cr.course c " + "left join fetch c.courseDefinition "
                + "left join fetch a.admissionAlternatives " + "left join fetch a.applications "
                + "left join fetch a.teaching " + "left join fetch a.admissionSchemaSettings "
                + "left join fetch a.admissionSchemaUploads " + "where a.organisationId in (select o.id from Organisation o where o.parentOrganisationId = :organisationId) ";
        StringBuilder sb = new StringBuilder(queryString);
        if (searchPhrase != null && searchPhrase.length() > 0) {
            sb.append(" AND (");
            sb.append("lower(a.courseRevision.course.code) like lower(:searchPhrase)");
            sb.append(" OR lower(a.name) like lower(:searchPhrase)");
            sb.append(" OR lower(a.courseRevision.name) like lower(:searchPhrase)");
            sb.append(")");

        }
        return sb.toString();
    }

    @Override
    protected AdmissionDTO createDTO(Admission bean) {
        return new AdmissionDTO(bean, useCourse, useAdmissionAlternatives, useApplicationStatusMap, useTeaching,
                useAdmissionSchemaSettings, useAdmissionSchemaUpload);
    }

    @Override
    protected ResultTransformer getQueryResultTransformer() {
        return Criteria.DISTINCT_ROOT_ENTITY;
    }
}.fetchList();

if (resultsList == null) {
    throw new DataAccessException(
            "DataManager: an error has occurred while trying to find Admission objects in database!");
}
logReturning(resultsList);
return resultsList;
}

This is my DTOListFetcher:

public abstract class DTOListFetcher<DTO, E> {

    private static final Log log = LogFactory.getLog(DTOListFetcher.class);

    /**
     * Return a map of parameters used for the hibernate query for this
     * {@code DTOListFetcher}. Parameters in the map are identified by parameter
     * name of {@code String} type. Parameter value can be any object or array
     * of objects.
     *
     * @return a map with query parameters.
     */
    protected abstract Map<String, Object> getParameters();

    /**
     * Returns query string for this {@code DTOListFetcher} implementation.
     *
     * @return a hibernate query string.
     */
    protected abstract String getQueryString();

    /**
     * Method to create a DTO object from the provided entity object.
     *
     * @param object - an entity object from which the resulting DTO object will
     * be created.
     * @return a DTO object.
     */
    protected abstract DTO createDTO(E object);

    /**
     * Empty implementation. Sublasses can override this method to apply extra
     * actions for the DTO object.
     *
     * @param session - reference to the current session.
     * @param item - entity item.
     * @param dto - DTO object to update.
     */
    protected void applyExtras(Session session, E item, DTO dto) {
    }

    /**
     * The main public method of the class. It Implements basic algorithm for
     * fetching list of items from the database. It calls some abstract methods
     * that require specific logic which is implemented in extending classes.
     *
     * @return a list of {@code DTO} objects.
     */
    public List<DTO> fetchList() {
        logEntered();
        Transaction tx = null;
        Session session = HibernateUtil.getSession();
        List<DTO> resultList = null;
        try {
            tx = session.beginTransaction();
            String queryString = getQueryString();
            Query query = session.createQuery(queryString);

            ResultTransformer resultTransformer = getQueryResultTransformer();
            if (resultTransformer != null) {
                query.setResultTransformer(resultTransformer);
            }

            Map<String, Object> parametersMap = getParameters();
            if (parametersMap != null && !parametersMap.isEmpty()) {
                for (String key : parametersMap.keySet()) {
                    Object param = parametersMap.get(key);
                    if (param instanceof Object[]) {
                        query.setParameterList(key, (Object[]) param);
                    }
                    else {
                        query.setParameter(key, param);
                    }
                }
            }
            List<E> results = query.list();
            if (results != null) {
                resultList = new ArrayList<DTO>();
                for (E item : results) {
                    DTO dto = createDTO(item);
                    applyExtras(session, item, dto);
                    resultList.add(dto);
                }
            } else {
                log.warn("The query returned NULL!");
            }
            commit(tx);
        } catch (Exception e) {
            handleException(e, tx);
            // Returned result will be NULL if error occurs!
            resultList = null;
        } finally {
            HibernateUtil.closeSession(session);
        }
        logReturning(resultList);
        return resultList;
    }

    private void logEntered() {
        log.info(MessageFormat.format("{0}: entered method ''{1}()''", this.getClass().getSimpleName(), getMethodName()));
    }

    /**
     * Get the method name for a depth in call stack. <br /> Utility function
     *
     * @param depth depth in the call stack (0 means current method, 1 means
     * call method, ...)
     * @return method name
     */
    private static String getMethodName() {
        final StackTraceElement[] ste = Thread.currentThread().getStackTrace();
        return ste[3].getMethodName(); //Thank you Tom Tresansky
    }

    private void commit(Transaction tx) {
        if (tx != null) {
            log.info("Committing transaction...");
            tx.commit();
            log.info("Transaction successfully commited.");
        }
    }

    private void handleException(Exception e, Transaction tx) {
        e.printStackTrace();
        if (tx != null) {
            log.info("rolling back transaction");
            tx.rollback();
            log.info("transaction successfully rolled back");
        }
    }

    public void logReturning(Object o) {
        String returnObject = o != null ? o.getClass().getSimpleName() : null;
        if (returnObject != null && o instanceof List) {
            if (((List) o).size() > 0) {
                returnObject = MessageFormat.format("{0}<{1}>", returnObject, ((List) o).get(0).getClass().getSimpleName());
            }
            returnObject = returnObject + ", total entries: " + ((List) o).size();
        }
        String className = this.getClass().getSimpleName();
        log.info(MessageFormat.format("{0}: returning from ''{1}()'' with result of type: {2}", className, getMethodName(), returnObject));
    }

    protected ResultTransformer getQueryResultTransformer() {
        return null;
    }
}

The Admission entity class:

@NamedQueries({ @NamedQuery(name = "getOngoingAdmissions", query = "from Admission a "
        + "where a.openingDate <= :referenceDate " + "and a.closingDate >= :referenceDate "
        + "and a.organisationId = :organisationId " + "order by a.openingDate") })
@Entity
@Table(name = "ADMISSION", schema = "SOACOURSE")
public class Admission implements Serializable {

    public static final String ADMISSION_TYPE_MANATT = "MANATT";
    public static final String ADMISSION_TYPE_DIRATT = "DIRATT";
    /*
     * Column names.
     */
    public static final String COLUMN_ID = "ID";
    public static final String COLUMN_ORGANISATION_ID = "ORGANISATION_ID";

    public static final String QUERY_ONGOING_ADMISSIONS = "getOngoingAdmissions";
    public static final String PARAM_REFERENCE_DATE = "referenceDate";
    public static final String PARAM_ORGANISATION_ID = "organisationId";
    public static final String PARAM_ID = "id";
    private static final long serialVersionUID = 995596202971143170L;
    /*
     * Attributes.
     */
    private String id;
    private String courseId;
    private int revisionNr;
    // private CourseExtended courseExtended;
    private CourseRevision courseRevision;
    private String name;
    private String admissionTypeCode;
    private String description;
    private Integer admissionType;
    private Date openingDate;
    private Date closingDate;
    private short publish;
    private Date publishOpeningDate;
    private Date publishClosingDate;
    private Integer admissionOfferValidSlot;
    private Integer admissionOfferSlotSlack;
    private String infoLink;
    private short emailVerification;
    private short emailAttachment;
    private String emailReply;
    private String emailSubject;
    private String emailContent;
    private Boolean responseRequired;
    private String information;
    private String helpLink;
    private short publishSelfService;
    private Integer ceiling;
    private String organisationId;
    private String productNumber;
    private Teaching teaching;
    private Set<AdmissionEmailDocument> admissionEmailDocuments = new HashSet<AdmissionEmailDocument>(0);
    private Set<Application> applications = new HashSet<Application>(0);
    private Set<AdmissionSurvey> admissionSurveys = new HashSet<AdmissionSurvey>(0);
    private Set<AdmissionAlternative> admissionAlternatives = new HashSet<AdmissionAlternative>(0);
    private Set<AdmissionArticle> admissionArticles = new HashSet<AdmissionArticle>(0);
    private AdmissionSchemaSettings admissionSchemaSettings;
    private Set<AdmissionSchemaUpload> admissionSchemaUploads = new HashSet<AdmissionSchemaUpload>(0);
    private List<AdmissionEmail> admissionEmails = new ArrayList<AdmissionEmail>(0);
    private Organisation organisation;

    // private Set<AdmissionTeaching> admissionTeachings = new HashSet<AdmissionTeaching>(0);
    public Admission() {}

    @Id
    @Column(name = "ID", unique = true, nullable = false, length = 28)
    public String getId() {
        return this.id;
    }

    public void setId(String id) {
        this.id = id;
    }

    @Column(name = "COURSE_ID", nullable = false, length = 28)
    public String getCourseId() {
        return courseId;
    }

    public void setCourseId(String courseId) {
        this.courseId = courseId;
    }

    @Column(name = "REVISION_NR", nullable = false, precision = 3)
    public int getRevisionNr() {
        return revisionNr;
    }

    public void setRevisionNr(int revisionNr) {
        this.revisionNr = revisionNr;
    }

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "TEACHING_ID")
    public Teaching getTeaching() {
        return this.teaching;
    }

    public void setTeaching(Teaching teaching) {
        this.teaching = teaching;
    }

    @Column(name = "NAME", nullable = false, length = 250)
    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Column(name = "ADMISSION_TYPE_CODE", nullable = false, length = 8)
    public String getAdmissionTypeCode() {
        return this.admissionTypeCode;
    }

    public void setAdmissionTypeCode(String admissionTypeCode) {
        this.admissionTypeCode = admissionTypeCode != null ? admissionTypeCode : "DIRATT";
    }

    @Column(name = "DESCRIPTION", length = 2000)
    public String getDescription() {
        return this.description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    @Column(name = "ADMISSION_TYPE", precision = 1, scale = 0)
    public Integer getAdmissionType() {
        return this.admissionType;
    }

    public void setAdmissionType(Integer admissionType) {
        this.admissionType = admissionType;
    }

    @Temporal(TemporalType.DATE)
    @Column(name = "OPENING_DATE", length = 7)
    public Date getOpeningDate() {
        return this.openingDate;
    }

    public void setOpeningDate(Date openingDate) {
        this.openingDate = openingDate;
    }

    @Temporal(TemporalType.DATE)
    @Column(name = "CLOSING_DATE", length = 7)
    public Date getClosingDate() {
        return this.closingDate;
    }

    public void setClosingDate(Date closingDate) {
        this.closingDate = closingDate;
    }

    @Column(name = "PUBLISH", nullable = false, precision = 1, scale = 0)
    public short getPublish() {
        return this.publish;
    }

    public void setPublish(Short publish) {
        this.publish = publish != null ? publish : 0;
    }

    @Temporal(TemporalType.DATE)
    @Column(name = "PUBLISH_OPENING_DATE", length = 7)
    public Date getPublishOpeningDate() {
        return this.publishOpeningDate;
    }

    public void setPublishOpeningDate(Date publishOpeningDate) {
        this.publishOpeningDate = publishOpeningDate;
    }

    @Temporal(TemporalType.DATE)
    @Column(name = "PUBLISH_CLOSING_DATE", length = 7)
    public Date getPublishClosingDate() {
        return this.publishClosingDate;
    }

    public void setPublishClosingDate(Date publishClosingDate) {
        this.publishClosingDate = publishClosingDate;
    }

    @Column(name = "ADMISSION_OFFER_VALID_SLOT", precision = 2, scale = 0)
    public Integer getAdmissionOfferValidSlot() {
        return this.admissionOfferValidSlot;
    }

    public void setAdmissionOfferValidSlot(Integer admissionOfferValidSlot) {
        this.admissionOfferValidSlot = admissionOfferValidSlot;
    }

    @Column(name = "ADMISSION_OFFER_SLOT_SLACK", precision = 2, scale = 0)
    public Integer getAdmissionOfferSlotSlack() {
        return this.admissionOfferSlotSlack;
    }

    public void setAdmissionOfferSlotSlack(Integer admissionOfferSlotSlack) {
        this.admissionOfferSlotSlack = admissionOfferSlotSlack;
    }

    @Column(name = "INFO_LINK")
    public String getInfoLink() {
        return this.infoLink;
    }

    public void setInfoLink(String infoLink) {
        this.infoLink = infoLink;
    }

    @Column(name = "EMAIL_VERIFICATION", nullable = false, precision = 1, scale = 0)
    public short getEmailVerification() {
        return this.emailVerification;
    }

    public void setEmailVerification(Short emailVerification) {
        this.emailVerification = emailVerification != null ? emailVerification : 0;
    }

    @Column(name = "EMAIL_ATTACHMENT", nullable = false, precision = 1, scale = 0)
    public short getEmailAttachment() {
        return this.emailAttachment;
    }

    public void setEmailAttachment(Short emailAttachment) {
        this.emailAttachment = emailAttachment != null ? emailAttachment : 0;
    }

    @Column(name = "EMAIL_REPLY")
    public String getEmailReply() {
        return this.emailReply;
    }

    public void setEmailReply(String emailReply) {
        this.emailReply = emailReply;
    }

    @Column(name = "EMAIL_SUBJECT")
    public String getEmailSubject() {
        return this.emailSubject;
    }

    public void setEmailSubject(String emailSubject) {
        this.emailSubject = emailSubject;
    }

    @Column(name = "EMAIL_CONTENT", length = 2000)
    public String getEmailContent() {
        return this.emailContent;
    }

    public void setEmailContent(String emailContent) {
        this.emailContent = emailContent;
    }

    @Column(name = "RESPONSE_REQUIRED", precision = 1, scale = 0)
    public Boolean getResponseRequired() {
        return this.responseRequired;
    }

    public void setResponseRequired(Boolean responseRequired) {
        this.responseRequired = responseRequired;
    }

    @Column(name = "INFORMATION", length = 2000)
    public String getInformation() {
        return this.information;
    }

    public void setInformation(String information) {
        this.information = information;
    }

    @Column(name = "HELP_LINK")
    public String getHelpLink() {
        return this.helpLink;
    }

    public void setHelpLink(String helpLink) {
        this.helpLink = helpLink;
    }

    @Column(name = "PUBLISH_SELF_SERVICE", nullable = false, precision = 1, scale = 0)
    public short getPublishSelfService() {
        return this.publishSelfService;
    }

    public void setPublishSelfService(Short publishSelfService) {
        this.publishSelfService = publishSelfService != null ? publishSelfService : 0;
    }

    @Column(name = "CEILING", precision = 4, scale = 0)
    public Integer getCeiling() {
        return this.ceiling;
    }

    public void setCeiling(Integer ceiling) {
        this.ceiling = ceiling;
    }

    @Column(name = "ORGANISATION_ID", length = 28)
    public String getOrganisationId() {
        return this.organisationId;
    }

    public void setOrganisationId(String organisationId) {
        this.organisationId = organisationId;
    }

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "admission")
    public Set<AdmissionEmailDocument> getAdmissionEmailDocuments() {
        return this.admissionEmailDocuments;
    }

    public void setAdmissionEmailDocuments(Set<AdmissionEmailDocument> admissionEmailDocuments) {
        this.admissionEmailDocuments = admissionEmailDocuments;
    }

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "admission")
    public Set<Application> getApplications() {
        return this.applications;
    }

    public void setApplications(Set<Application> applications) {
        this.applications = applications;
    }

    // @OneToMany(fetch = FetchType.LAZY, mappedBy = "admission")
    // public Set<AdmissionTeaching> getAdmissionTeachings() {
    // return this.admissionTeachings;
    // }
    //
    // public void setAdmissionTeachings(Set<AdmissionTeaching> admissionTeachings) {
    // this.admissionTeachings = admissionTeachings;
    // }
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "admission")
    public Set<AdmissionSurvey> getAdmissionSurveys() {
        return this.admissionSurveys;
    }

    public void setAdmissionSurveys(Set<AdmissionSurvey> admissionSurveys) {
        this.admissionSurveys = admissionSurveys;
    }

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "admission")
    @OrderBy(AdmissionAlternative.PROPERTY_SORT_ORDER + " ASC")
    public Set<AdmissionAlternative> getAdmissionAlternatives() {
        return this.admissionAlternatives;
    }

    public void setAdmissionAlternatives(Set<AdmissionAlternative> admissionAlternatives) {
        this.admissionAlternatives = admissionAlternatives;
    }

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "admission")
    public Set<AdmissionArticle> getAdmissionArticles() {
        return this.admissionArticles;
    }

    public void setAdmissionArticles(Set<AdmissionArticle> admissionArticles) {
        this.admissionArticles = admissionArticles;
    }

    @OneToOne(fetch = FetchType.LAZY, mappedBy = "admission")
    public AdmissionSchemaSettings getAdmissionSchemaSettings() {
        return this.admissionSchemaSettings;
    }

    public void setAdmissionSchemaSettings(AdmissionSchemaSettings admissionSchemaSettings) {
        this.admissionSchemaSettings = admissionSchemaSettings;
    }

    // @ManyToOne(fetch = FetchType.LAZY)
    // @JoinColumns({
    // @JoinColumn(name = "COURSE_ID", referencedColumnName = "COURSE_ID", insertable = false,
    // updatable = false),
    // @JoinColumn(name = "REVISION_NR", referencedColumnName = "REVISION_NR", insertable = false,
    // updatable = false)
    // })
    // public CourseExtended getCourseExtended() {
    // return this.courseExtended;
    // }
    //
    // public void setCourseExtended(CourseExtended courseExtended) {
    // this.courseExtended = courseExtended;
    // }
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumns({
            @JoinColumn(name = "COURSE_ID", referencedColumnName = "COURSE_ID", nullable = false, insertable = false, updatable = false),
            @JoinColumn(name = "REVISION_NR", referencedColumnName = "REVISION_NR", nullable = false, insertable = false, updatable = false) })
    public CourseRevision getCourseRevision() {
        return this.courseRevision;
    }

    public void setCourseRevision(CourseRevision courseRevision) {
        this.courseRevision = courseRevision;
    }

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "admission")
    public Set<AdmissionSchemaUpload> getAdmissionSchemaUploads() {
        return admissionSchemaUploads;
    }

    public void setAdmissionSchemaUploads(Set<AdmissionSchemaUpload> admissionSchemaUploads) {
        this.admissionSchemaUploads = admissionSchemaUploads;
    }

    @OneToMany(fetch = FetchType.LAZY, mappedBy = AdmissionEmail.PROPERTY_ADMISSION)
    public List<AdmissionEmail> getAdmissionEmails() {
        return admissionEmails;
    }

    public void setAdmissionEmails(List<AdmissionEmail> admissionEmails) {
        this.admissionEmails = admissionEmails;
    }

    @Transient
    public boolean isDiratt() {
        return ADMISSION_TYPE_DIRATT.equals(admissionTypeCode);
    }

    @Transient
    public boolean isManatt() {
        return ADMISSION_TYPE_MANATT.equals(admissionTypeCode);
    }

    @Column(name = "PRODUCT_NUMBER", length = 32)
    public String getProductNumber() {
        return productNumber;
    }

    public void setProductNumber(String productNumber) {
        this.productNumber = productNumber;
    }

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = COLUMN_ORGANISATION_ID, referencedColumnName = Organisation.COLUMN_ADDRESS_OWNER_ID, insertable = false, updatable = false)
    public Organisation getOrganisation() {
        return organisation;
    }

    public void setOrganisation(Organisation organisation) {
        this.organisation = organisation;
    }
}

I don't know why it's failing when the casing is correct. Or I may have overlooked something. I hope someone can help.

Thanks!

EDIT

I forgot to mention that it has worked for the last few version and it worked yesterday but not today.


Solution

  • Looks like a problem with this

    sb.append("lower(a.courseRevision.course.code) like lower(:searchPhrase)");
    

    You can't use a.courseRevision.course.code because you don't have the a.courseRevision alias.

    Maybe c.code.