The question is: how do I make GORM generate left joins instead of inner joins in this particular example?
Testbed:
Given classes A, B and C:
class A{
B someObject
}
class B{
C importantObject
}
class C{
boolean interestingFlag
}
I want to list all the elements of A class that:
- their B.C object is null OR
- their B.C object interestingFlag value is false
What I tried so far:
This approach produces correct list of A where B.C is null (conditional 2 commented out) OR correct list of A where B.C.interestingFlag = false (no matter if conditional 1 is commented out or not). When both conditionals are uncommented it returns only a list of elements where A.B.C.interestingFlag = false (A.B.C = null conditional is ignored)
// approach 1 (conditional 1 is ignored)
def result = A.withCriteria{
someObject{
or{
isNull('importantObject') // conditional 1, works well when conditional 2 is commented out
importantObject{
eq('interestingFlag', false) // conditional 2, works well alone, discards conditional 1 when both of them are uncommented
}
}
}
}
Edit: As requested in comment I'm pasting a hibernate generated sql:
Hibernate: select this_.id as id1_2_, this_.version as version1_2_,
this_.some_object_id as some3_1_2_, someobject1_.id as id2_0_,
someobject1_.version as version2_0_, someobject1_.important_object_id as
important3_2_0_, importanto2_.id as id0_1_, importanto2_.version as version0_1_,
importanto2_.interesting_flag as interest3_0_1_ from a this_
inner join b someobject1_ on this_.some_object_id=someobject1_.id
inner join c importanto2_ on someobject1_.important_object_id=importanto2_.id
where ((someobject1_.important_object_id is null or (importanto2_.interesting_flag=?)))
When I copy and paste it in the pgAdmin query tool directly with a few things changed (inner joins changed to left joins, and provided the interestingFlag = "false" parameter) everything works as I wanted (I get both A.B.C = null and A.B.C.importantFlag = false objects)
Hibernate: select this_.id as id1_2_, this_.version as version1_2_,
this_.some_object_id as some3_1_2_, someobject1_.id as id2_0_,
someobject1_.version as version2_0_, someobject1_.important_object_id as
important3_2_0_, importanto2_.id as id0_1_, importanto2_.version as version0_1_,
importanto2_.interesting_flag as interest3_0_1_ from a this_
left join b someobject1_ on this_.some_object_id=someobject1_.id
left join c importanto2_ on someobject1_.important_object_id=importanto2_.id
where ((someobject1_.important_object_id is null or (importanto2_.interesting_flag=false)))
Tested and working solution:
I was able to achieve left outer joins only with HQL
Use left join to achieve this. This should work, but I haven't tested it live.
Eidt: based on this post: http://grails.1312388.n4.nabble.com/CriteriaBuilder-DSL-Enhancements-td4644831.html this should also work:
Please post your results on both solutions.
Edit 2: This is a query that is exactly a situation you've described, but differs from your examples. You must start from here, use showSql to debug generated SQLs and fiddle with left joins.