Been working with Hibernate for a while now, but until recently I haven't had to dig very deeply into the Criteria queries stuff. Now I do, and it looks like the manual has been updated fairly recently - I don't remember seeing the stuff on Subqueries the last time I looked a few months ago.
I thought I understood from the examples how DetachedQuery and Subqueries are to be used, but I must be missing something because they aren't behaving the way I expect them to.
I'm building a Criteria query to return a list of TepEligibility objects based on a variable set of tests. TepEligibility is defined as follows:
Code:
public class TepEligibility {
private Long id;
private Long pidm;
private Timestamp activityDate;
private DeptRecmdType deptRecmd;
private PortfolioStatusType portfolioStatus;
private TecAction tecAction;
private boolean tepApplicationReceived;
private StudentTeachingYr studentTeachingYr;
// snip getters and setters
}
pidm is an identifier which acts as the primary key on another object (I know, why haven't I modeled it as a one-to-one? There are some issues because I have to work with both a legacy ERP and our own database, which are running on databases from different venders. At any rate, it's outside the scope of this post). I am using a criteria query to retrieve appropriate instances of TepEligibility based on which options the user selects:
Code:
Criteria c = getSession().createCriteria(TepEligibility.class, "e");
...
if (portfolio != null) {
c.add(Expression.eq("e.portfolioStatus", PortfolioStatusType.get(portfolio)));
}
if (tecAction != null) {
c.add(Expression.eq("e.tecAction.action", TecActionType.get(tecAction)));
}
if (studentTeachingYr != null) {
c.add(Expression.eq("e.studentTeachingYr.academicYear", studentTeachingYr));
return c.list();
}
So far so good. The next option I need to code is more complicated than the above, requiring a sub-query. First, I declared the following DetachedCriteria:
Code:
DetachedCriteria studentsPassingEng110 = DetachedCriteria.forClass(StudentGrade.class, "grade")
.setProjection(Property.forName("student.pidm"))
.add(Property.forName("subjectCode").eq("ENG"))
.add(Property.forName("courseNumber").eq("110"));
This returns pidms for all students who have received a grade for ENG 110. I tested the query with the following code, and received a big list of Long objects, as expected:
Code:
List r = studentsPassingEng110.getExecutableCriteria(getSession()).list();
Figuring all was right with the world, I attempted to use this with my original criteria query as follows:
Code:
if (requiredClasses != null && requiredClasses.equals("true")) {
c.add(Subqueries.in("e.pidm", studentsPassingEng110));
}
Unfortunately, c.list() in this case results in the following stack trace:
Code:
java.lang.ClassCastException: java.lang.String
at org.hibernate.type.LongType.set(LongType.java:40)
at org.hibernate.type.NullableType.nullSafeSet(NullableType.java:62)
at org.hibernate.type.NullableType.nullSafeSet(NullableType.java:44)
at org.hibernate.loader.Loader.bindPositionalParameters(Loader.java:1115)
at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1177)
at org.hibernate.loader.Loader.doQuery(Loader.java:390)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:218)
at org.hibernate.loader.Loader.doList(Loader.java:1593)
at org.hibernate.loader.Loader.list(Loader.java:1577)
at org.hibernate.loader.criteria.CriteriaLoader.list(CriteriaLoader.java:111)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1322)
at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:300)
(snip unimportant remainder of stack trace)
The really screwy part is the SQL that Hibernate generates (I've formatted it by hand for readability, but it is otherwise unchanged):
Code:
select this_.id as id0_,
this_.activity_date as activity2_12_0_,
this_.pidm as pidm12_0_,
this_.dept_recmd as dept4_12_0_,
this_.portfolio_status as portfolio5_12_0_,
this_.tec_action as tec6_12_0_,
this_.tec_action_comment as tec7_12_0_,
this_.tec_action_date as tec8_12_0_,
this_.tep_application_received as tep9_12_0_,
this_.student_teaching_year as student10_12_0_
from tched_tep_eligibility this_
where ? in (
select this0__.SHRTCKN_PIDM as y0_
from tched_banner_grade this0__
where this0__.SHRTCKN_SUBJ_CODE=?
and this0__.SHRTCKN_CRSE_NUMB=?)
Wha? Why is that first parameter in there at all? Shouldn't that read 'where this_.pidm in ( ...) instead? I presume this is related to the ClassCastException as well, with the String param that's *supposed* to be checked against SHRTCKN_SUBJ_CODE actually getting stuck in that first where clause.
What's the deal? Did I miss something important that's causing Hibernate to get confused, or is this a bug?