GORM createCriteria 具有一对多关系
几个小时以来,我试图弄清楚如何使用一种“必须在列表中”标准创建一个标准。
如果我减少我的代码,我有以下两个域类:
Hotel - 我想要检索的基域类:
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 域对象
列表后,我就不再尝试了。因此,我不会有 totalCount
参数(我的分页功能需要该参数),
因此,我陷入了编写自己的查询和/或使用 GORM 方法解决此问题之间的困境。也可能是我对到底如何这应该如何工作有点困惑。
对于任何通知或解决方案,我将非常高兴。
谢谢, Christopher
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()
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()
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
即时构建标准:
在纯 SQL 中,这也不是更容易:
您可以使用具有如下语义的
intersect
查询进行更优化:一些示例 此处。
编辑:我尝试构建第二种类型标准但失败了 - 我认为无法构建
具有 count
类型的条件。不管怎样,它会比几个in
-s慢,因为它必须计数
所有酒店的
设施
代码>.Build the criteria on the fly:
In pure SQL, it's not much easier:
You could go probably more optimally with
intersect
query with a semantic like this:Some sample here.
edit: I tried to construct second-type criteria and failed - I see no way to build
having count
-type condition. Anyway, it's going to be slower then severalin
-s, as it will have tocount
Amenities
for all thehotels
.更新,这应该给你一个拥有所有设施的酒店列表,试试这个:
UPDATE, this should give you a list of hotels that has all amenties, try this: