I think this should work:
def usersAndIncompleteProjects = Users.withCriteria {
projects {
isNull( completionDate )
}
}
That should just return you the Users with incomplete projects, and the projects
property for each User
will only contain the incomplete projects. If you want the Users to have all of their projects loaded, I believe you need to use an alias
Testing...
Given the User class:
package criteriatest
class User {
String name
static hasMany = [ projects: Project ]
}
And the Project class:
package criteriatest
class Project {
String name
Date completionDate
static belongsTo = User
static constraints = {
completionDate( nullable:true )
}
}
This integration test passes (hopefully the asserts explain it)
package criteriatest
import grails.test.*
class UserTests extends GroovyTestCase {
protected void setUp() {
super.setUp()
User.withSession { session ->
def tim = new User( name:'tim' )
def dave = new User( name:'dave' )
[ tim, dave ]*.save()
def project1 = new Project( name:'project 1', completionDate:null )
def project2 = new Project( name:'project 2', completionDate:new Date() )
tim.addToProjects project1
tim.addToProjects project2
[ project1, project2 ]*.save()
session.flush()
session.clear()
}
}
protected void tearDown() {
super.tearDown()
}
void testQuery() {
def usersAndIncompleteProjects = User.withCriteria {
projects {
isNull 'completionDate'
}
order 'name', 'asc'
}
// We get two users back (users with no projects get returned as well)
assert usersAndIncompleteProjects.size() == 2
// First user (dave) has no projects
assert usersAndIncompleteProjects[0].projects.size() == 0
// Second user (tim) has one project (with a null completionDate)
assert usersAndIncompleteProjects[1].projects.size() == 1
// Check it's the right project
assert usersAndIncompleteProjects[1].projects*.name == [ 'project 1' ]
}
}
(this is the sql the criteria query executes in this instance):
select
this_.id as id1_1_,
this_.version as version1_1_,
this_.name as name1_1_,
projects3_.user_projects_id as user1_3_,
projects_a1_.id as project2_3_,
projects_a1_.id as id0_0_,
projects_a1_.version as version0_0_,
projects_a1_.completion_date as completion3_0_0_,
projects_a1_.name as name0_0_
from
user this_
left outer join
user_project projects3_
on this_.id=projects3_.user_projects_id
left outer join
project projects_a1_
on projects3_.project_id=projects_a1_.id
where
(
projects_a1_.completion_date is null
)
order by
this_.name asc