Grails准则投影 - 获取行数

18

我有一个酒店实体:

class Hotel {
City city
}

现在,我需要给定城市的酒店数量。

可以通过以下方式完成:

def hotels = Hotel.findAllByCity(city)
def cnt = hotels.size()

但这是非常糟糕的方式。使用条件似乎更好,但我不知道如何实现...

2个回答

49

Dave是正确的,你可以使用countBy*方法进行简单计数。如果你需要超过两个条件,则必须返回criteria apiHQL或SQL。尤其是在一个活跃且不断发展的代码库中,通常需要超过两个条件。

这里是一个例子,说明如何使用Criteria api 进行投影查询(projections)

def c = Hotel.createCriteria()

def hotelCount = c.get {
    projections {
        count('id')
    }
    gt("stars", 2)          
    eq("city", city)            
    eq("deleted", false)

}

或者(更加优雅地),您甚至可以像下面这样使用Criteria#count:

def c = Hotel.createCriteria()

def hotelCount = c.count {
    gt("stars", 2)          
    eq("city", city)            
    eq("deleted", false)

}

仅为完整起见:

class Hotel {
    City city
    Boolean deleted = false
    Integer stars
}

class City {
    String name
}

使用 build-test-data 插件 进行集成测试。

import grails.test.*

class HotelTests extends GrailsUnitTestCase {

    void testCriteria() {
        City city1 = City.build(name:'one')
        assertNotNull(city1)
        City city2 = City.build(name:'two')
        assertNotNull(city1)

        Hotel fiveStarHotel= Hotel.build(city:city1, deleted:false, stars:5)
        assertNotNull(fiveStarHotel)

        Hotel hotelInCity2 = Hotel.build(city:city2, deleted:false, stars:5)
        assertNotNull(hotelInCity2)

        Hotel deletedHotel = Hotel.build(city:city1, deleted:true, stars:5)
        assertNotNull(deletedHotel)

        Hotel threeStarHotel = Hotel.build(city:city1, deleted:false, stars:3)
        assertNotNull(threeStarHotel)

        Hotel oneStarHotel = Hotel.build(city:city1, deleted:false, stars:1)
        assertNotNull(oneStarHotel)

        def c = Hotel.createCriteria()

        def hotelCount = c.get {
            projections {
                count('id')
            }
            gt("stars", 2)          
            eq("city", city1)           
            eq("deleted", false)

        }
        assertEquals(2, hotelCount) //should only find the 5 and 3 star hotel

        def c2 = Hotel.createCriteria()
        hotelCount = c2.count {
            gt("stars", 2)          
            eq("city", city1)           
            eq("deleted", false)

        }
        assertEquals(2, hotelCount) //should only find the 5 and 3 star hotel
    }
}

为了简洁起见,我该怎么把这些条件放到一行里?我需要为每个语句添加分号(;)吗? - Robert A Henru
我相信你可以这样做:Hotel.createCriteria().count { gt("stars", 2); eq("city", city); eq("deleted", false) } 但我还没有尝试过。 - Colin Harrington
如果我想找出哪些城市有不止一家酒店,该怎么办? - Nathan Dunn
看起来在 GORM 标准查询中不支持 "having" 子句,但在 HQL 中是支持的。 - Nathan Dunn

24

领域对象上有动态计数器和查找器:

Hotel.countByCity(city)

当然,更多细节请查阅用户指南


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接