GORM createCriteria с отношением один ко многим - PullRequest
0 голосов
/ 22 августа 2011

, так как пару часов я пытаюсь выяснить, как создать критерий с критерием , который должен быть в списке .

Если я уменьшу свой код, то получуследующие два класса домена:

Отель - Базовый класс домена, который я хочу получить:

class Hotel {

    static hasMany = [rooms: Room, amenities: HotelAmenity]

}

HotelAmenity - В отеле естьсписок удобств.

class HotelAmenity {

    String name

}

# 1 Мой первый подход был примерно таким:

PagedResultList pgl = Hotel.createCriteria().list(max: limit, offset: offset) {
    // ..
    and {
        amenities {
            'in'("id",myLongIdsList)
    }
}

Это работает.Но в этом случае я получаю каждый возвращенный отель, который содержит хотя бы одного указанного анемия.Но моя желанная цель - найти отели, которые имеют все указанные удобства.

# 2 Поэтому я попытался выполнить следующие действия:

// ..
amenities {
    condition.hotelAmenities.collect { it.toLong() }.each {
        and {
            eq('id', it)
        }
}

Но этокод выглядит так, как будто он испортил набор результатов, потому что он всегда возвращает пустой список, если определено более одной функции.Между прочим, в этом сценарии с одной услугой все отели, которые содержит мой список результатов, не будут иметь никаких других удобств в своем списке удобств, кроме того, который я искал - даже при том, что многие из них назначены.Я совершенно не понимаю этого поведения.

# 3 Еще один подход, который я пробовал, - играть с listDistinct вместо list.Но я больше не пробовал это делать, когда узнал, что я не получаю PagedResultList, а возвращается список hotel domain objects.И поэтому у меня не будет параметра totalCount (который мне нужен для моей функциональности разбивки на страницы)

Итак, я застрял между написанием собственного запроса и / или решением этой проблемы с помощью подхода GORM.Может также случиться так, что я немного запутался по поводу , как именно это должно работать.

Для любого уведомления или решения я был бы очень рад.

Спасибо, Кристофер

PS: я использую Grails версии 1.3.7

PPS: Если какая-либо информация отсутствует, сообщите мне.

РЕДАКТИРОВАТЬ

Вот решение, с которым я пришел:

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()

Ответы [ 2 ]

2 голосов
/ 22 августа 2011

Построить критерии на лету:

def neededAmenities = ...

PagedResultList pgl = Hotel.createCriteria().list(max: limit, offset: offset) {
    // ..
    amenities {
        and {
            neededAmenities.each { needed ->
                idEq (needed.id)
            }
        }
    }
}

В чистом SQL это не намного проще:

where exists(amenities.id == XXX) and exists(amenities.id == YYY) and (...) ... 

Возможно, вы могли бы пойти более оптимально с запросом intersect с такой семантикой:

where intersect(
    select id from amenities where ..., 
    (:neededAmenities)) 
= (:neededAmenities)

Пример здесь .

edit: Я пытался создать критерии второго типа, но потерпел неудачу - Я не вижу способа построить условие having count -type . В любом случае, это будет медленнее, чем несколько in -с, так как для всех hotels.

потребуется count Amenities.
0 голосов
/ 22 августа 2011

ОБНОВЛЕНИЕ, это должно дать вам список отелей, которые имеют все удобства, попробуйте это:

def amenitySize = HotelAmenity.list()?.size()
def hotelList = Hotel.createCriteria().list{
    sizeEq("amenities", amenitySize)
}
...