GORM createCriteria具有一对多关系

时间:2011-08-22 08:42:22

标签: list grails gorm one-to-many createcriteria

因为几个小时后我试图找出如何使用必须在列表中标准创建标准。

如果我减少了我的代码,我有两个域类:

酒店 - 我要检索的基本域类:

class Hotel {

    static hasMany = [rooms: Room, amenities: 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)
        }
}

但是这段代码看起来像是弄乱​​了结果集,因为它总是会返回一个空列表,如果有多个amenitiies定义的话。 顺便说一句,在这个单一的设施方案中,我的结果列表中包含的所有酒店在他们的设施列表中都没有任何其他设施,但是我搜索的那个 - 即使分配了大量的酒店。我完全不明白这种行为。

#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 个答案:

答案 0 :(得分:2)

即时建立标准:

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)

一些示例here

编辑:我尝试构建第二类标准但失败了 - I see no way to build having count-type condition。无论如何,它会慢于几个in - s,因为对于所有count,它必须Amenities hotels

答案 1 :(得分:0)

更新,这应该会给你一个包含所有设施的酒店列表,试试这个:

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