since a couple of hours I try to figure out how to create a criteria with a kind of must-be-in-list criterion.
If I reduce my code I have following two domain classes:
Hotel - The base domain class that I want to retrieve:
class Hotel {
static hasMany = [rooms: Room, amenities: HotelAmenity]
}
HotelAmenity - A hotel has a list of amenities.
class HotelAmenity {
String name
}
#1 My first approach was something like this:
PagedResultList pgl = Hotel.createCriteria().list(max: limit, offset: offset) {
// ..
and {
amenities {
'in'("id",myLongIdsList)
}
}
This works. But in this case I get every hotel returned that contains at least one of the specified anemities. But my desired goal is to retrieve hotels that have all specified amenities only.
#2 So I tried following
// ..
amenities {
condition.hotelAmenities.collect { it.toLong() }.each {
and {
eq('id', it)
}
}
But this code looks like it's messing up the result set, because it always returns an empty list, if there are more then one amenitiies defined. By the way, in this one-amenity scenario all hotels that my result list contains won't have any other amenity in their amenities-list but that one I searched for - even though plenty of them are assigned. I totally don't understand this behaviour.
#3 Another approach I tried was playing around with listDistinct
instead of list
. But I did not try this any further once I recognized that I don't get a PagedResultList
but a list of hotel domain objects
returned. And so I won't have the totalCount
parameter (which I need for my pagination functionality)
So, I am stucked between writing my own query and/or solving this issue with a GORM approach. It could also be that I am a bit confused about how exactly this should be work.
For any notice or solution I would be very glad.
Thanks, Christopher
PS: I use Grails version 1.3.7
PPS: If any informations are missing please let me know.
EDIT
This is now the solution I come along with:
Map sqlParams = [:]
String mySql = "SELECT SQL_CALC_FOUND_ROWS hotel.id FROM hotel WHERE "
if(hotelAmenities.size()>0) {
String commaSeperatedAmenities = hotelAmenities.toString()
// the amenity IDs as comma seperates list so we can use them in the `IN` statement (ie 1,3,6,7)
commaSeperatedAmenities = commaSeperatedAmenities.substring(1,commaSeperatedAmenities.length()-1)
mySql += '( SELECT COUNT(hotel_amenities_id) from hotel_hotel_amenity ' +
'WHERE hotel_amenities_id = hotel.id AND hotel_amenity_id IN ' +
'(' + comaAmentities + ') ) = ' + condition.hotelAmenities.size()
}
mySql += 'LIMIT :offset, :limit'
sqlParams.put("offset",offset)
sqlParams.put("limit",limit)
def mresult = sqlInstance.rows(mySql,sqlParams)
List<Hotel> hotels = Hotel.getAll(mresult.collect {it.id})
int calcFoundRows = sqlInstance.rows("SELECT FOUND_ROWS()").get(0).get("FOUND_ROWS()").toString().toInteger()