I’m trying to write a query for my Grails application that selects all the instances of Apple that are “related” to an instance of Orange. Here the word “related” means all the instances of Banana that are associated with an instance of Apple are associated with some combination of instances of Cherry which are associated with the instance of Orange we are concerned with. I have looked at the question here, but my query is a little more complex and I’m not seeing how to apply the given answer to my problem.
Here are the classes I’m dealing with:
class Apple {
static hasMany = [ bananas: Banana ]
}
class Banana {
}
class Cherry {
static hasMany = [ bananas: Bannna ]
}
class Orange {
static hasMany = [ cherries: Cherry ]
}
In picture form that looks like this:

In the scenario 1 shown below, the desired query would only return “Apple 1” because all the instances of Banana that are related to “Apple 2” are not related to “Orange 1” through some combination of instances of “Cherry”.

In the scenario 2 shown below, the desired query would return “Apple 1” and “Apple 2” because all the instances of Banana that are related to “Apple 2” are related to “Orange 1” through some combination of instances of “Cherry”.

Here is the query I have been working with:
Apple.executeQuery(
"SELECT DISTINCT apples
FROM Apple apples
INNER JOIN apples.banannas banannas
WHERE banannas IN(
SELECT DISTINCT banannas
FROM Cherry cherries
INNER JOIN cherries.banannas banannas
WHERE cherries IN(
SELECT DISTINCT cherries
FROM Orange orange
INNER JOIN orange.cherries cherries
WHERE orange =:myOrange
)
)
ORDER BY apples.id ASC",
myOrange: myOrange
)
The problem is that my query returns “Apple 1” and “Apple 2” for both scenario 1 and 2.
UPDATE #1:
As requested, here is the SQL generated by the HQL query. Sorry for the fruity obfuscation <<< pun
SELECT DISTINCT apple0_.id AS id10_,
apple0_.version AS version10_,
apple0_.description AS descript3_10_,
apple0_.apple_priority_type_id AS apple4_10_,
apple0_.apple_status_type_id AS apple5_10_,
apple0_.internal_need_date AS internal6_10_,
apple0_.name AS name10_
FROM apple apple0_
INNER JOIN apple_priority_type applepri1_
ON apple0_.apple_priority_type_id = applepri1_.id
INNER JOIN apple_status_type applesta2_
ON apple0_.apple_status_type_id = applesta2_.id
INNER JOIN apple_banana banana3_
ON apple0_.id = banana3_.apple_bananas_id
INNER JOIN banana banana4_
ON banana3_.banana_id = banana4_.id
WHERE banana4_.id IN (SELECT DISTINCT banana7_.id
FROM cherry plum5_
INNER JOIN cherry_banana banana6_
ON plum5_.id = banana6_.cherry_bananas_id
INNER JOIN banana banana7_
ON banana6_.banana_id = banana7_.id
WHERE plum5_.id IN (SELECT DISTINCT plum10_.id
FROM orange orange8_
INNER JOIN orange_cherry
plum9_
ON
orange8_.id = plum9_.orange_cherrys_id
INNER JOIN cherry plum10_
ON
plum9_.cherry_id = plum10_.id
WHERE orange8_.id = 248))
ORDER BY apple0_.id ASC
LIMIT 100
UPDATE #2:
I actually have a way to make this work with HQL, but it isn’t a nice one liner like I have in other places where I’m finding all of some type related to an instance of some other type. Here is my work around:
def bananas= myOrange.cherries.bananas.flatten().unique()
def apples = Apple.getAll().collectMany{ !it.bananas.isEmpty() && bananas.containsAll( it.bananas ) ? [ it ] : [] }.flatten().unique()
namedParams.put( "apples", apples )
if( !apples.isEmpty() ) {
apples = Apple.executeQuery( "SELECT DISTINCT apples FROM Apple apples WHERE apples IN(:apples) ${additionalQuery} ORDER BY ${sortname} ${sortorder}", namedParams )
}
return apples
That’s because if your Apple have at least one relation with a banana, will always return.
What you need to do is exclude from your results that apples where not exists a banana related with your Cherry. You will have to look if your database have a function like oracle minus.
EDIT: This query removes from the list that apples that have a banana that’s not in the cherries bananas.
Note: I not checked the performance of this.