HQL Query on Set Property

David picture David · May 3, 2011 · Viewed 13.1k times · Source

Suppose that I have the following HBM mapping:

<class name="Student" table="student">
    <set name="classes" table="student_classes" cascade="none">
        <key column="studentId" />
        <many-to-many column="classId" class="org.myCompany.myClass" />
    </set>
</class>

In my student POJO, I have the following:

private Set<myClass> classes = new HashSet<myClass>();
public Set<myClass> getClasses() { return classes; }
public void setClasses(Set<myClass> classes) { this.classes = classes; }

I want to run the following HQL query:

select count(*) from Student where classes.className = :myClassName

However, hibernate throws the following exception:

ERROR [service-j2ee-4] PARSER.reportError(33) |  Invalid path: 'classes.className'
ERROR [service-j2ee-4] PARSER.reportError(33) | <AST>:0:0: unexpected end of subtree
ERROR [service-j2ee-4] PARSER.reportError(33) |  left-hand operand of a binary operator was null
org.hibernate.hql.ast.QuerySyntaxException: Invalid path: 'classes.className' [select count(*) from Student where classes.className = :myClassName  and  1=1]

Is it possible to run a hibernate query which returns results based on properties of a Set? In the above example, we might want to query for all students who are taking 'Algebra I' or another course?

Edit: I enabled the appropriate debug mode to get Hibernate to output it's actual SQL query and here is the query that it generates:

select count(*) as col_0_0_ 
from student student0_, student_classes student1_, classes student2_

where student0_.studentId=student1_.studentId and student1_.classId=student2_.classId and student2_.className LIKE 'algebra' and 1=1;

Answer

JB Nizet picture JB Nizet · May 3, 2011
select count(s.id) from Student s
inner join s.classes clazz
where clazz.className = :myClassName

Here's how I reason about it : classes is a Set, and thus doesn't have a className property. Once you traverse the relationship using a join, you get an alias on the myClass entity, which has a className property.

Note: classes in Java should always begin with an upper-case letter. Rename myClass to MyClass.