To paraphrase a Grails example, I'm trying to fetch a list of books with no author. The author could be anonymous, or simply not set (null). So far I can search by value, I can search by null, but I can't seem to do both at once. Using the Book and Author example, let's say I have the following books...
To find books by "Anonymous" I could do this...
Book.withCriteria {
author {
eq('name', 'Anonymous')
}
}
Returns "O: A Presidential Novel"
All is well. Now to find books with no author I can do this...
Book.withCriteria {
isNull('author')
}
Returns "Beowulf"
That's fine too. So to fetch both books I should 'or' them together...
Book.withCriteria {
or {
isNull('author')
author {
eq('name', 'Anonymous')
}
}
}
Returns "O: A Presidential Novel"
Why doesn't this return both books? I'm using Grails 2.3.7 with Hibernate 3.6.10.16
Update: I've found a query that works though I'm confused how it's different...
Book.withCriteria {
or {
isNull('author')
// author {
// eq('name', 'Anonymous')
// }
sqlRestriction('{alias}.author_id = (select author_id from authors where name = ?)', 'Anonymous')
}
}
As mentioned in another answer, association queries like that map to an inner join at the SQL level. You can instead do a left outer join using createAlias
:
def list = c.list {
createAlias('author', 'a', CriteriaSpecification.LEFT_JOIN)
or {
isNull('author')
eq('a.name', 'Anonymous')
}
}